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;

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 := to FStoredItems.Count - 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 := ;
ComboBox.Top := ;
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;

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;
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 := to FStoredItems.Count - do begin
// check if the current one contains the text in edit
// if ContainsText(FStoredItems[I], Text) then
if Pos( Text, FStoredItems[I])> 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), );
if (Items<>nil) and (Items.Count>) then begin
ItemIndex := ;
end else begin
ItemIndex := -;
end;
Text := xText;
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;
xList:TStringList;
begin // here's one combo created dynamically
ComboBox := TComboBox.Create(Self);
ComboBox.Parent := Self;
ComboBox.Left := ;
ComboBox.Top := ;
ComboBox.Width := Width-;
// 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 := ; // 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.

How to make a combo box with fulltext search autocomplete support?的更多相关文章

  1. 【转】VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)

    原文网址:http://www.jizhuomi.com/software/189.html 上一节鸡啄米讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常 ...

  2. 下拉列表框Combo Box

    Combo Box/Combo Box Ex 组合窗口是由一个输入框和一个列表框组成.创建一个组合窗口可以使用成员函数: BOOL CListBox::Create( LPCTSTR lpszText ...

  3. Win32 SDK Combo Box

    如下图所示,显示了三种不同风格的Combo Box样式.当然,现在这样看不出第一种与第三种之间的区别,但是第二种与其他两种的区别是明显的,第二种的列表框始终是出于现实状态的. Combo Box: 一 ...

  4. Check Box、Radio Button、Combo Box控件使用

    Check Box.Radio Button.Combo Box控件使用 使用控件的方法 1.拖动控件到对话框 2. 定义控件对应的变量(值变量或者控件变量) 3.响应控件各种消息 Check Box ...

  5. Missing styles. Is the correct theme chosen for this layout? Use the Theme combo box above the layou

    android无法静态显示ui效果. Missing styles. Is the correct theme chosen for this layout? Use the Theme combo ...

  6. VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)

    上一节鸡啄米讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常见,例如,在Windows系统的控制面板上设置语言或位置时,有很多选项,用来进行选择的控件就是 ...

  7. Combo Box的简单使用(Win32)

    1 SendMessage函数向窗口发送消息 LRESULT SendMessage( HWND hWnd,     // handle to destination window UINT Msg, ...

  8. Creating Dialogbased Windows Application (4) / 创建基于对话框的Windows应用程序(四)Edit Control、Combo Box的应用、Unicode转ANSI、Open File Dialog、文件读取、可变参数、文本框自动滚动 / VC++, Windows

    创建基于对话框的Windows应用程序(四)—— Edit Control.Combo Box的应用.Unicode转ANSI.Open File Dialog.文件读取.可变参数.自动滚动 之前的介 ...

  9. WPF Combo box 获取选择的Tag

    string str1 = ((ComboBoxItem)this.cboBoxRate1553B.Items[this.cboBoxRate1553B.SelectedIndex]).Tag.ToS ...

随机推荐

  1. Nginx源码分析--epoll模块

    Nginx采用epoll模块实现高并发的网络编程,现在对Nginx的epoll模块进行分析. 定义在src/event/modules/ngx_epoll_module.c中 1. epoll_cre ...

  2. Nginx源码分析--数组(转)

    原文地址:http://blog.csdn.net/marcky/article/details/5747431 备注:以下关于Nginx源码的分析基于淘宝开源项目Tengine. Nginx中对数组 ...

  3. 构建基于TCP的应用层通信模型

    各层的关系如下图,表述的是两个应用或CS间通信的过程:   通常使用TCP构建应用时,需要考虑传输层的通信协议,以便应用层能够正确识别消息请求.比如,一个请求的内容很长(如传文件),那肯定要分多次发送 ...

  4. POJ 3253 Fence Repair(哈夫曼编码)

    题目链接:http://poj.org/problem?id=3253 题目大意: 有一个农夫要把一个木板钜成几块给定长度的小木板,每次锯都要收取一定费用,这个费用就是当前锯的这个木版的长度 给定各个 ...

  5. sed实践

    后来也找到一篇文章讲的很详细: http://www.cnblogs.com/ctaixw/p/5860221.html --------------------------------------- ...

  6. logstash通过tcp收集日志

    (1)标准输入输出tcp模块 1.修改配置文件 #vim /etc/logstash/conf.d/tcp.conf input { tcp { port => "5600" ...

  7. thinkphp5.0目录结构

    下载最新版框架后,解压缩到web目录下面,可以看到初始的目录结构如下: project 应用部署目录 ├─application 应用目录(可设置) │ ├─common 公共模块目录(可更改) │ ...

  8. IntelliJ IDEA 编译程序出现 非法字符 的 解决方法(转)

    百度到很多方法,比如(删了文件重新建:先改成GBK再UTF8:粘贴到notpad++上改utf8),但都没有解决问题.下面这种方法确实有效,先记下来,如果有其他好方法将来在补充…… 文章来源:  ht ...

  9. Am335x SD卡 启动制作

    1.网上下载DiskGenius(分区工具) 2.将4Gsd卡分区3个,boot,rootfs,user 3.boot分区大概在62M左右如图所示 将编译好的MLO.u-boot.img.uEnv.t ...

  10. 【BZOJ 4171】 4171: Rhl的游戏 (高斯消元)

    4171: Rhl的游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 74  Solved: 33[Submit][Status][Discuss] ...