如何使用 Delphi TComboBox 自动完成和限制列表

How to both autocomplete and limit to list with Delphi TComboBox

假设我想 select 'london' 来自英国城镇的大列表

设置

Combo1.AutoComplete := true;
Combo1.Style := csDropdown;

如果我输入 'l',然后输入 'o',然后输入 'n',它最初 select 是第一个以 'l' 开头的项目,然后是第一个以两个字母 'lo' 开头的项目,然后是第一个以 'lon' 开头的项目。这正是我想要的行为——这很好。

但是我也可以输入我喜欢的任何文本,无论它是否在列表中 - 这很糟糕。

设置

Combo1.AutoComplete := true;
Combo1.Style := csDropdownList;

我无法输入任何我喜欢的文字,只能输入 select 列表中的一项 - 这很好。

但现在如果我输入 'l',然后输入 'o',然后输入 'n',它最初 select 是第一个以 'l' 开头的项目,然后selects 以 'o' 开头的第一个项目和以 'n' 开头的第一个项目,而不是使用所有三个字母和 selecting 以 [=37= 开头的第一个项目].

我怎样才能同时完成这两件事?

即我想限制为 selecting 列表中的项目,但也能够开始输入并在我目前输入的所有字母上使用它 select。

这里是小"hack"在代码中控制ComboBox中的文本:

uses ... StrUtils;

...

procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: Char);
var
  s, t: string;
  i, l: Integer;
  f: Boolean;
begin
  // Skip functional keys
  if Key < ' ' then
    Exit;

  // Get text which can be in the combo after key pressed
  i := ComboBox1.SelStart;
  l := ComboBox1.SelLength;
  t := ComboBox1.Text;
  s := Copy(t, 1, i) + Key + Copy(t, i + l + 1, Length(t));

  // Check is this text corresponds to the values list
  f := False;
  for i := 0 to ComboBox1.Items.Count - 1 do
    if StrUtils.StartsStr(s, ComboBox1.Items[i]) then
    begin
      f := True;
      Break;
    end;

  // If not - cancel key
  if not f then
    Key := #0;
end;

PS:适用于Combo1.Style := csDropdown;案例

使用第二个选项

Combo1.AutoComplete := true;
Combo1.Style := csDropdownList;

并将自动完成延迟从默认的 500 增加到更大一些,让用户有时间在自动完成开始之前键入第二个和第三个等字符。