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. vue单选,多选,多选的内容显示在页面可删除

    vue做单选只能选一个 <template> <div class="list"> <!-- 多行多列单选 --> <span>只能 ...

  2. 修改系统时间为UTC时间

    1 拷贝时区文件 cp /usr/share/zoneinfo/Etc/GMT /etc/localtime 2 修改/etc/profile 在最后添加 TZ="Etc/GMT" ...

  3. Oracle数据库(64位) 及 PLSQL(64位)的组合安装【第一篇】

    目前PC端普遍使用64位操作系统,64位操作系统在性能上比32位更佳,但是兼容性上则不如32的操作系统,Oracle提供了64和32两种版本,而PLsql工具则只有32位,在这篇文章详细的讲述了如何在 ...

  4. python基础(11)--面向对象

    1.概述 面向过程:根据业务的逻辑从上到下写代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发更快更好更强 面向过程编程最易被初学者接受 ...

  5. mysql字符编码相关

    mysql> show variables like '%character%'; +--------------------------+--------------------------- ...

  6. 十 使用dict和set

    dict Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 举个例子,假设要根据同学的名字 ...

  7. shell-sed命令详解(转)

    (转自http://blog.csdn.net/wl_fln/article/details/7281986) Sed简介 sed是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时 ...

  8. python配置libsvm

    转载博文:win10(64-bit) + python3.6.0(64-bit) 配置libsvm-3.22 https://blog.csdn.net/weixin_35884839/article ...

  9. https请求过程

    我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取.所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议. HTTPS简介 HTTPS其实是有两部分组成:HTTP + SSL ...

  10. 【BZOJ 4361】 4361: isn (DP+树状数组+容斥)

    4361: isn Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 218  Solved: 126 Description 给出一个长度为n的序列A( ...