How can I filter the contents of a combo box based on what's been typed?

送分小仙女□ 提交于 2019-12-21 12:41:23

问题


We have a combo box with more than 100 items.

We want to filter out the items as we enter characters in combo box. For example if we entered 'ac' and click on the drop down option then we want it to display items starting with 'ac' only.

How can I do this?


回答1:


Maybe you'd be happier using the autocompletion features built in to the OS. I gave an outline of how to do that here previously. Create an IAutoComplete object, hook it up to your combo box's list and edit control, and the OS will display a drop-down list of potential matches automatically as the user types. You won't need to adjust the combo box's list yourself.




回答2:


To expand on Rob's answer about using the OnChange event, here is an example of how to do what he suggests.

procedure TForm1.FormCreate(Sender: TObject);
begin
  FComboStrings := TStringList.Create;
  FComboStrings.Add('Altair');
  FComboStrings.Add('Alhambra');
  FComboStrings.Add('Sinclair');
  FComboStrings.Add('Sirius');
  FComboStrings.Add('Bernard');
  FComboStrings.Sorted := True;
  ComboBox1.AutoComplete := False;
  ComboBox1.Items.Text := FComboStrings.Text;
  ComboBox1.Sorted := True;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FComboStrings);
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
var
  Filter: string;
  i: Integer;
  idx: Integer;
begin
  // Dropping down the list puts the text of the first item in the edit, this restores it
  Filter := ComboBox1.Text;
  ComboBox1.DroppedDown := True;
  ComboBox1.Text := Filter;
  ComboBox1.SelStart := Length(Filter);

  for i := 0 to FComboStrings.Count - 1 do
    if SameText(LeftStr(FComboStrings[i], Length(ComboBox1.Text)), ComboBox1.Text) then
    begin
      if ComboBox1.Items.IndexOf(FComboStrings[i]) < 0 then
        ComboBox1.Items.Add(FComboStrings[i]);
    end
    else
    begin
      idx := ComboBox1.Items.IndexOf(FComboStrings[i]);
      if idx >= 0 then
        ComboBox1.Items.Delete(idx);
    end;
end;



回答3:


My brief contribution working with objects in the combobox:

procedure FilterComboBox(Combo: TComboBox; DefaultItems: TStrings);

  function Origin: TStrings;
  begin
    if Combo.Tag = 0 then
    begin
      Combo.Sorted := True;
      Result := TStrings.Create;
      Result := Combo.Items;
      Combo.Tag := Integer(Result);
    end
    else
      Result := TStrings(Combo.Tag);
  end;

var
  Filter: TStrings;
  I: Integer;
  iSelIni: Integer;
begin
  if(Combo.Text <> EmptyStr) then
  begin
    iSelIni:= Length(Combo.Text);
    Filter := TStringList.Create;
    try
      for I := 0 to Origin.Count - 1 do
        if AnsiContainsText(Origin[I], Combo.Text) then
          Filter.AddObject(Origin[I], TObject(Origin.Objects[I]));

        Combo.Items.Assign(Filter);
        Combo.DroppedDown:= True;
        Combo.SelStart := iSelIni;
        Combo.SelLength := Length(Combo.Text);
    finally
      Filter.Free;
    end;
  end
  else
    Combo.Items.Assign(DefaultItems);
end;



回答4:


You can handle the combo box's OnChange event. Keep a master list of all items separate from the UI control, and whenever the combo box's edit control changes, adjust the combo box's list accordingly. Remove items that don't match the current text, or re-add items from the master list that you removed previously.




回答5:


As Rob already answered, you could filter on the OnChange event, see the following code example. It works for multiple ComboBoxes.

{uses}
  Contnrs, StrUtils;

type
  TForm1 = class(TForm)
    ComboBox1: TComboBox;
    ComboBox2: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure ComboBoxChange(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FComboLists: TList;
    procedure FilterComboBox(Combo: TComboBox);
  end;

implementation

{$R *.dfm}

procedure TForm1.ComboBoxChange(Sender: TObject);
begin
  if Sender is TComboBox then
    FilterComboBox(TComboBox(Sender));
end;

procedure TForm1.FilterComboBox(Combo: TComboBox);

  function Origin: TStrings;
  begin
    if Combo.Tag = 0 then
    begin
      Combo.Sorted := True;
      Result := TStringList.Create;
      Result.Assign(Combo.Items);
      FComboLists.Add(Result);
      Combo.Tag := Integer(Result);
    end
    else
      Result := TStrings(Combo.Tag);
  end;

var
  Filter: TStrings;
  I: Integer;
begin
  Filter := TStringList.Create;
  try
    for I := 0 to Origin.Count - 1 do
      if AnsiStartsText(Combo.Text, Origin[I]) then
        Filter.Add(Origin[I]);
    Combo.Items.Assign(Filter);
    Combo.SelStart := Length(Combo.Text);
  finally
    Filter.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FComboLists := TObjectList.Create(True);
  // For Each ComboBox, set AutoComplete at design time to false:
  ComboBox1.AutoComplete := False;
  ComboBox2.AutoComplete := False;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FComboLists.Free;
end;


来源:https://stackoverflow.com/questions/6667054/how-can-i-filter-the-contents-of-a-combo-box-based-on-whats-been-typed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!