Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 499
naren Avatar asked Jul 12 '11 15:07

naren


3 Answers

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.

like image 62
Rob Kennedy Avatar answered Sep 28 '22 07:09

Rob Kennedy


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;
like image 41
Marjan Venema Avatar answered Sep 28 '22 05:09

Marjan Venema


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;
like image 38
Andrés Velasco Avatar answered Sep 28 '22 06:09

Andrés Velasco