如何制作具有全文搜索自动完成支持的组合框? [英] How to make a combo box with fulltext search autocomplete support?

查看:30
本文介绍了如何制作具有全文搜索自动完成支持的组合框?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望用户能够输入 TComboBox 项目中的第二个或第三个单词,并使该项目显示在 AutoSuggest 下拉选项中

例如,组合框包含项目:

  • 约翰·布朗先生
  • 阿曼达·布朗夫人
  • 布莱恩·琼斯先生
  • 萨曼莎·史密斯夫人

当用户输入Br"时,下拉菜单显示:

  • 约翰·布朗先生
  • 阿曼达·布朗夫人
  • 布莱恩·琼斯先生

当用户输入Jo"时,下拉菜单会显示:

  • 约翰·布朗先生
  • 布莱恩·琼斯先生

问题在于 AutoSuggest 功能仅包含下拉列表中以用户输入内容开头的项目,因此在上面的示例中,下拉列表中不会显示任何内容.

是否可以使用 IAutoComplete 接口和/或其他相关接口来解决此问题?

解决方案

以下示例使用了 TComboBox 组件.与原始类的主要区别在于,项目存储在单独的 StoredItems 属性中,而不是
Items 像往常一样(因为简单而使用).

StoredItems 正在被 监视OnChange 事件,每当您更改它们时(例如通过添加或删除此字符串列表),即使下拉组合
列表,当前过滤器也会反映它.

这里的重点是抓住 WM_COMMAND 消息通知 CBN_EDITUPDATE 每当组合编辑文本更改但尚未呈现时发送.当它到达时,您只需在 StoredItems 列表中搜索您在组合编辑中输入的内容并填写 Items 匹配的属性.

对于文本搜索,使用 ContainsText 所以搜索不区分大小写.忘了提,
AutoComplete 功能必须关闭,因为它有自己的、不受欢迎的逻辑用于此目的.

unit Unit1;界面用途Windows、消息、SysUtils、变体、类、图形、控件、表单、对话框、StdCtrls、StrUtils、ExtCtrls;类型TComboBox = 类(StdCtrls.TComboBox)私人的FStoredItems: TStringList;过程过滤器项目;过程 StoredItemsChange(Sender: TObject);过程 SetStoredItems(const Value: TStringList);过程 CNCommand(var AMessage: TWMCommand);消息 CN_COMMAND;民众构造函数创建(AOwner:TComponent);覆盖;析构函数销毁;覆盖;属性 StoredItems:TStringList 读取 FStoredItems 写入 SetStoredItems;结尾;类型TForm1 = 类(TForm)ComboBox1:TComboBox;程序 FormCreate(Sender: TObject);私人的{ 私人声明}民众{ 公开声明 }结尾;无功Form1:TForm1;执行{$R *.dfm}构造函数 TComboBox.Create(AOwner: TComponent);开始遗传;自动完成:= 假;FStoredItems := TStringList.Create;FStoredItems.OnChange := StoredItemsChange;结尾;析构函数 TComboBox.Destroy;开始FStoredItems.Free;遗传;结尾;程序 TComboBox.CNCommand(var AMessage: TWMCommand);开始//我们必须处理来自我们祖先的一切遗传;//如果我们收到 CBN_EDITUPDATE 通知如果 AMessage.NotifyCode = CBN_EDITUPDATE 那么//用匹配项填充项目过滤项目;结尾;程序 TComboBox.FilterItems;无功I:整数;选择:TS选择;开始//存储当前组合编辑选择发送消息(句柄,CB_GETEDITSEL,WPARAM(@Selection.StartPos),LPARAM(@Selection.EndPos));//从项目更新开始Items.BeginUpdate;尝试//如果组合编辑不为空,则清除项目//并搜索 FStoredItems如果文本<>'' 然后开始//清除所有项目项目.清除;//遍历所有这些对于 I := 0 到 FStoredItems.Count - 1 做//检查当前是否包含编辑中的文本如果 containsText(FStoredItems[I], Text) 那么//如果是,则将其添加到项目中Items.Add(FStoredItems[I]);结尾//否则组合编辑为空别的//所以我们将使用我们在 FStoredItems 中的所有内容Items.Assign(FStoredItems)最后//完成项目更新Items.EndUpdate;结尾;//并恢复上次组合编辑选择SendMessage(句柄,CB_SETEDITSEL,0,MakeLParam(Selection.StartPos,Selection.EndPos));结尾;程序 TComboBox.StoredItemsChange(Sender: TObject);开始如果已分配(FStoredItems) 那么过滤项目;结尾;程序 TComboBox.SetStoredItems(const Value: TStringList);开始如果已分配(FStoredItems) 那么FStoredItems.Assign(Value)别的FStoredItems := 值;结尾;程序 TForm1.FormCreate(Sender: TObject);无功组合框:TComboBox;开始//这是一个动态创建的组合组合框:= TComboBox.Create(Self);ComboBox.Parent := Self;组合框.左:= 10;ComboBox.Top := 10;ComboBox.Text := 'Br';//这里是如何填充 StoredItemsComboBox.StoredItems.BeginUpdate;尝试ComboBox.StoredItems.Add('John Brown');ComboBox.StoredItems.Add('Mrs Amanda Brown');ComboBox.StoredItems.Add('布莱恩·琼斯先生');ComboBox.StoredItems.Add('萨曼莎·史密斯夫人');最后ComboBox.StoredItems.EndUpdate;结尾;//这里是如何从表单分配组合框的项目//到 StoredItems;请注意,如果您要使用它,则必须执行//在你在组合编辑中输入一些东西之前,因为输入//可能会过滤项目,因此它们会被修改ComboBox1.StoredItems.Assign(ComboBox1.Items);结尾;结尾.

I would like a user to be able to type in the second or third word from a TComboBox item 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 := 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.

这篇关于如何制作具有全文搜索自动完成支持的组合框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆