我希望用户能够从TComboBox项目中输入第二个或第三个单词,并且该项目将显示在AutoSuggest下拉列表选项中
例如,组合框包含以下项目:
>约翰·布朗先生
>阿曼达·布朗夫人
>布赖恩·琼斯先生
> Samantha Smith夫人
>约翰·布朗先生
>阿曼达·布朗夫人
>布赖恩·琼斯先生
>约翰·布朗先生
>布赖恩·琼斯先生
问题是AutoSuggest功能只包括下拉列表中的项目,从用户输入的内容开始,因此在上述示例中,下拉列表中不会出现任何内容。
可以使用IAutoComplete接口和/或其他相关的接口来解决这个问题吗?
解决方法
以下示例使用插入的
TComboBox
组件类。与原始类的主要区别在于,项目存储在单独的StoredItems属性中,而不是通常为
Items
(由于简单而使用)。
StoredItems被OnChange
事件监视,每当您更改它们(例如通过从该字符串列表中添加或删除)时,即使当Combolist被删除时,当前的过滤器也将反映出来。
这里的要点是抓住WM_COMMAND
消息通知CBN_EDITUPDATE
,每当组合编辑文本更改但尚未呈现时,该消息通知正在发送。当它到达时,您只需搜索StoredItems列表中您在组合编辑中键入的内容,并使用匹配填充Items
属性。
使用ContainsText
进行文本搜索,因此搜索不区分大小写。忘了提及,AutoComplete
功能必须关闭,因为它有自己的,不欢迎的逻辑为此目的。
unit Unit1; interface uses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls,StrUtils,ExtCtrls; type TComboBox = class(StdCtrls.TComboBox) private FStoredItems: TStringList; procedure FilterItems; procedure StoredItemsChange(Sender: TObject); procedure SetStoredItems(const Value: TStringList); procedure CNCommand(var AMessage: TWMCommand); message CN_COMMAND; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property StoredItems: TStringList read FStoredItems write SetStoredItems; end; type TForm1 = class(TForm) ComboBox1: TComboBox; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} constructor TComboBox.Create(AOwner: TComponent); begin inherited; AutoComplete := False; FStoredItems := TStringList.Create; FStoredItems.OnChange := StoredItemsChange; end; destructor TComboBox.Destroy; begin FStoredItems.Free; inherited; end; procedure TComboBox.CNCommand(var AMessage: TWMCommand); begin // we have to process everything from our ancestor inherited; // if we received the CBN_EDITUPDATE notification if AMessage.NotifyCode = CBN_EDITUPDATE then // fill the items with the matches FilterItems; end; procedure TComboBox.FilterItems; var I: Integer; Selection: TSelection; begin // store the current combo edit selection SendMessage(Handle,CB_GETEDITSEL,WPARAM(@Selection.StartPos),LPARAM(@Selection.EndPos)); // begin with the items update Items.BeginUpdate; try // if the combo edit is not empty,then clear the items // and search through the FStoredItems if Text <> '' then begin // clear all items Items.Clear; // iterate through all of them for I := 0 to FStoredItems.Count - 1 do // check if the current one contains the text in edit if ContainsText(FStoredItems[I],Text) then // and if so,then add it to the items Items.Add(FStoredItems[I]); end // else the combo edit is empty else // so then we'll use all what we have in the FStoredItems Items.Assign(FStoredItems) finally // finish the items update Items.EndUpdate; end; // and restore the last combo edit selection SendMessage(Handle,CB_SETEDITSEL,MakeLParam(Selection.StartPos,Selection.EndPos)); end; procedure TComboBox.StoredItemsChange(Sender: TObject); begin if Assigned(FStoredItems) then FilterItems; end; procedure TComboBox.SetStoredItems(const Value: TStringList); begin if Assigned(FStoredItems) then FStoredItems.Assign(Value) else FStoredItems := Value; end; procedure TForm1.FormCreate(Sender: TObject); var ComboBox: TComboBox; begin // here's one combo created dynamically ComboBox := TComboBox.Create(Self); ComboBox.Parent := Self; ComboBox.Left := 10; ComboBox.Top := 10; ComboBox.Text := 'Br'; // here's how to fill the StoredItems ComboBox.StoredItems.BeginUpdate; try ComboBox.StoredItems.Add('Mr John Brown'); ComboBox.StoredItems.Add('Mrs Amanda Brown'); ComboBox.StoredItems.Add('Mr Brian Jones'); ComboBox.StoredItems.Add('Mrs Samantha Smith'); finally ComboBox.StoredItems.EndUpdate; end; // and here's how to assign the Items of the combo Box from the form // to the StoredItems; note that if you'll use this,you have to do // it before you type something into the combo's edit,because typing // may filter the Items,so they would get modified ComboBox1.StoredItems.Assign(ComboBox1.Items); end; end.