如何在C++Builder中实现支持全文搜索自动补全的ComboBox控件
C++Builder实现带全文搜索自动补全ComboBox的问题修复
以下是代码中存在的问题及修复方案:
存在的核心错误
- 消息响应函数
CNCommand声明与绑定错误:VCL自定义消息响应函数需要使用MESSAGE_HANDLER宏绑定到消息映射,且参数必须为引用传递,值传递会导致内存访问错误。 - 循环逻辑越界:
FilterItems函数中遍历FStoredItems的条件写为i < FStoredItems->Count - 1,会漏掉最后一个元素,极端情况会触发越界访问。 - 逻辑运算符错误:
KeyPress函数中判断按键范围的逻辑运算符&&误写为按位与&,导致条件判断完全失效。 - 字符串列表赋值逻辑错误:
SetStoredItems函数中直接将外部传入的TStringList指针赋值给内部成员FStoredItems,会导致内存泄漏、野指针问题。 CB_GETEDITSEL传参错误:该消息要求传入存储光标起始、结束位置的变量指针,直接传值无法获取正确的光标位置,后续操作会触发异常。- 缺少下拉列表自动弹出逻辑:过滤完成后没有主动弹出下拉列表展示匹配结果,功能不完整。
修复后代码
头文件代码
class PACKAGE TSmartComboBox : public TComboBox { private: TStringList* FStoredItems; bool dofilter; int storeditemindex; void FilterItems(); void __fastcall StoredItemsChange(TObject* Sender); void __fastcall CNCommand(TWMCommand& AMessage); // 修改为引用传递 protected: BEGIN_MESSAGE_MAP MESSAGE_HANDLER(CN_COMMAND, TWMCommand, CNCommand) // 绑定消息映射 END_MESSAGE_MAP(TComboBox) DYNAMIC void __fastcall KeyPress(System::WideChar &Key); DYNAMIC void __fastcall CloseUp(void); DYNAMIC void __fastcall Click(void); public: __fastcall TSmartComboBox(TComponent* Owner); __fastcall ~TSmartComboBox(); void InitSmartCombo(); __published: void __fastcall SetStoredItems(TStringList* Value); __property TStringList* StoredItems = {read = FStoredItems, write = SetStoredItems}; };
实现文件代码
static inline void ValidCtrCheck(TSmartComboBox *) { new TSmartComboBox(NULL); } //--------------------------------------------------------------------------- __fastcall TSmartComboBox::TSmartComboBox(TComponent* Owner) : TComboBox(Owner) { FStoredItems = new TStringList(); dofilter = false; storeditemindex = -1; } __fastcall TSmartComboBox::~TSmartComboBox() { delete FStoredItems; } void __fastcall TSmartComboBox::SetStoredItems(TStringList* Value) { // 统一使用Assign,不直接接管外部指针 FStoredItems->Assign(Value); } void __fastcall TSmartComboBox::KeyPress(System::WideChar &Key) { // 修正逻辑运算符为&& if(dofilter && (Key >= 13 && Key <= 27)) { if(Items->Count != 0 && !DroppedDown) { SendMessage(Handle, CB_SHOWDROPDOWN, 1, 0); } } } void __fastcall TSmartComboBox::CloseUp(void) { AnsiString x; if(dofilter) { if(Items->Count == 1 && ItemIndex == 0) { Text = Items->Strings[ItemIndex]; } else if((Text != "" && ItemIndex != -1 && Text != Items->Strings[ItemIndex]) || (Text == "" && ItemIndex == 0)) { storeditemindex = ItemIndex; x = Text; ItemIndex = Items->IndexOf(Text); if(ItemIndex == -1) { Text = x; } } else { storeditemindex = -1; } } } void __fastcall TSmartComboBox::Click(void) { if(dofilter) { if(storeditemindex != -1) { ItemIndex = storeditemindex; } storeditemindex = -1; } } void TSmartComboBox::InitSmartCombo() { FStoredItems->OnChange = NULL; FStoredItems->Assign(Items); AutoComplete = false; FStoredItems->OnChange = StoredItemsChange; dofilter = true; storeditemindex = -1; } void __fastcall TSmartComboBox::StoredItemsChange(TObject* Sender) { if(FStoredItems) { FilterItems(); } } void TSmartComboBox::FilterItems() { int i; DWORD startSel, endSel; // 修正CB_GETEDITSEL传参方式,传变量地址 SendMessage(Handle, CB_GETEDITSEL, WPARAM(&startSel), LPARAM(&endSel)); Items->BeginUpdate(); if (Text != "") { Items->Clear(); // 修正循环条件,去掉-1 for (i = 0; i < FStoredItems->Count; i++) { if(Pos(UpperCase(Text), UpperCase(FStoredItems->Strings[i])) > 0) { Items->Add(FStoredItems->Strings[i]); } } } else { Items->Assign(FStoredItems); } Items->EndUpdate(); // 恢复光标位置 SendMessage(Handle, CB_SETEDITSEL, 0, MakeLParam(startSel, endSel)); // 自动弹出下拉列表 if(Items->Count > 0 && !DroppedDown) { SendMessage(Handle, CB_SHOWDROPDOWN, 1, 0); } } void __fastcall TSmartComboBox::CNCommand(TWMCommand& AMessage) { if(AMessage.NotifyCode == CBN_EDITUPDATE && dofilter) { FilterItems(); } // 调用基类默认处理 TComboBox::Dispatch(&AMessage); } //--------------------------------------------------------------------------- namespace Comboboxsmart { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {__classid(TSmartComboBox)}; RegisterComponents(L"polpress", classes, 0); } }
使用方法
把控件添加到窗体后,先给ComboBox的Items添加全部选项,然后调用一次InitSmartCombo()即可启用搜索功能。
内容的提问来源于stack exchange,提问作者ppitu
相关产品推荐
相关产品推荐

