博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
How to make a combo box with fulltext search autocomplete support?
阅读量:7175 次
发布时间:2019-06-29

本文共 9794 字,大约阅读时间需要 32 分钟。

I would like a user to be able to type in the second or third word from a TComboBoxitem and for that item to appear in the AutoSuggest dropdown options

For example, a combo box contains the items:

  • Mr John Brown
  • Mrs Amanda Brown
  • Mr Brian Jones
  • Mrs Samantha Smith

When the user types "Br" the dropdown displays:

  • Mr John Brown
  • Mrs Amanda Brown
  • Mr Brian Jones

and when the user types "Jo" the dropdown displays:

  • Mr John Brown
  • Mr Brian Jones

The problem is that the AutoSuggest functionality only includes items in the dropdown list that begin with what the user has input and so in the examples above nothing will appear in the dropdown.

Is it possible to use the IAutoComplete interface and/or other related interfaces to get around this issue?

The following example uses the interposed class of the TComboBox component. The main difference from the original class is that the items are stored in the separate StoredItems property instead of

the Items as usually (used because of simplicity).

The StoredItems are being watched by the OnChange event and whenever you change them (for instance by adding or deleting from this string list), the current filter will reflect it even when the combo

list is dropped down.

The main point here is to catch the WM_COMMAND message notification CBN_EDITUPDATE which is being sent whenever the combo edit text is changed but not rendered yet. When it arrives, you just search through the StoredItems list for what you have typed in your combo edit and fill the Items property with matches.

For text searching is used the ContainsText so the search is case insensitive. Forgot to mention,

the AutoComplete feature has to be turned off because it has its own, unwelcomed, logic for this purpose.

unit Unit1;interfaceuses  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, 0, 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.

 

Thanks for the heart! With a little reworking, I think that is quite right.

 

unit Unit1;interfaceuses  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;  protected  public    constructor Create(AOwner: TComponent); override;    destructor Destroy; override;    property StoredItems: TStringList read FStoredItems write SetStoredItems;  end;type  TForm1 = class(TForm)    procedure FormCreate(Sender: TObject);  private  public  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 begin // fill the items with the matches FilterItems; end; end;{}procedure TComboBox.FilterItems; type TSelection = record StartPos, EndPos: Integer; end; var I: Integer; Selection: TSelection; xText: string; 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 begin // check if the current one contains the text in edit // if ContainsText(FStoredItems[I], Text) then if Pos( Text, FStoredItems[I])>0 then begin // and if so, then add it to the items Items.Add(FStoredItems[I]); end; end; end else begin // else the combo edit is empty // so then we'll use all what we have in the FStoredItems Items.Assign(FStoredItems) end; finally // finish the items update Items.EndUpdate; end; // and restore the last combo edit selection xText := Text; SendMessage(Handle, CB_SHOWDROPDOWN, Integer(True), 0); if (Items<>nil) and (Items.Count>0) then begin ItemIndex := 0; end else begin ItemIndex := -1; end; Text := xText; SendMessage(Handle, CB_SETEDITSEL, 0, 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; xList:TStringList; begin // here's one combo created dynamically ComboBox := TComboBox.Create(Self); ComboBox.Parent := Self; ComboBox.Left := 8; ComboBox.Top := 8; ComboBox.Width := Width-16;// ComboBox.Style := csDropDownList; // here's how to fill the StoredItems ComboBox.StoredItems.BeginUpdate; try xList:=TStringList.Create; xList.LoadFromFile('list.txt'); ComboBox.StoredItems.Assign( xList); finally ComboBox.StoredItems.EndUpdate; end; ComboBox.DropDownCount := 24; // 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 ComboBox.StoredItems.Assign(ComboBox.Items); end;end.

 

转载地址:http://dwbzm.baihongyu.com/

你可能感兴趣的文章
rpm,yum,权限
查看>>
更新yum到 163
查看>>
Office 2019 & Office 2016 下载地址
查看>>
tomcat应用转到weblogic上时的问题
查看>>
国外程序员是如何准备面试的
查看>>
Zookeeper监控之——node-zk-browser
查看>>
我的友情链接
查看>>
10个最酷的linux单行命令
查看>>
myeclipse 10 在mac retina 屏幕下显示字体模糊解决方法
查看>>
创建自定义的指令
查看>>
javascript对象中判断属性
查看>>
git删除分支与合并分支
查看>>
Python元组
查看>>
HD TUNE以及所有其他硬盘检测工具都不能使用的情况
查看>>
Linux内存分析
查看>>
vSphere 5.5 vCenter迁移至分布式交换机
查看>>
排序 遍历
查看>>
第二次作业
查看>>
Mysql主从复制
查看>>
高斯消元法解非奇异线性方程组的MATLAB程序
查看>>