Как я могу отфильтровать содержимое поля со списком в зависимости от того, что было напечатано? - PullRequest
6 голосов
/ 12 июля 2011

У нас есть поле со списком из более чем 100 предметов.

Мы хотим отфильтровать элементы по мере ввода символов в поле со списком. Например, если мы ввели «ac» и нажали на опцию выпадающего меню, мы хотим, чтобы он отображал элементы, начинающиеся только с «ac».

Как я могу это сделать?

Ответы [ 5 ]

9 голосов
/ 12 июля 2011

Может быть, вы были бы счастливее, используя функции автозаполнения, встроенные в ОС.Я дал план, как это сделать здесь ранее.Создайте объект IAutoComplete, подключите его к списку вашего поля со списком и отредактируйте элемент управления, и ОС автоматически отобразит раскрывающийся список возможных совпадений при вводе пользователем.Вам не нужно настраивать список со списком самостоятельно.

4 голосов
/ 12 июля 2011

Чтобы расширить ответ Роба об использовании события OnChange, вот пример того, как сделать то, что он предлагает.

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;
2 голосов
/ 31 октября 2012

Мой краткий вклад в работу с объектами в выпадающем списке:

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;
1 голос
/ 12 июля 2011

Как уже ответил Роб, вы можете отфильтровать событие OnChange, см. Следующий пример кода. Работает для нескольких ComboBox.

{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;
1 голос
/ 12 июля 2011

Вы можете обработать событие OnChange поля со списком.Держите основной список всех элементов отдельно от элемента управления пользовательского интерфейса, и всякий раз, когда изменяется элемент управления редактирования поля со списком, корректируйте список поля со списком соответствующим образом.Удалите элементы, которые не соответствуют текущему тексту, или повторно добавьте элементы из основного списка, который вы удалили ранее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...