自动完成Combobox小结

来源:互联网 发布:淘宝返利最高的软件 编辑:程序博客网 时间:2024/05/12 10:43

工作需要做一个自动完成combobox,就是用户在编辑框输入的时候,下拉框能自动选择用户输入最相近的一项,同时编辑框给出自动完成功能。

途中遇到很多小麻烦,网上下了一大堆源码,总结了不少经验,不敢独享,以飨读者。

首先继承一个CCombobox的类,响应以下消息处理:

[cpp] view plaincopy
  1. BEGIN_MESSAGE_MAP(CComboCompletion, CComboBox)  
  2.     //{{AFX_MSG_MAP(CComboCompletion)  
  3.     //ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelChange)  
  4.     ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown)  
  5.     ON_CONTROL_REFLECT(CBN_EDITUPDATE, OnEditUpdate)  
  6.     //}}AFX_MSG_MAP  
  7. END_MESSAGE_MAP()  

注意,不宜响应CBN_SELCHANGE,而是应该响应CBN_EDITUPDATE,前者让组合框的爸爸去解决就好了。。。

 

在处理消息之前,我们应该对消息进行一下判断,并不是用户的每次按键都是有意义的。

同时,有些消息如果不想传给父亲,就要中断消息链。在我的例子里,回车键会发给父窗口的编辑器导致换行,所以我这里阻止了回车消息的传递。

[c-sharp] view plaincopy
  1. // 重写PreTranslateMessage函数以预处理消息  
  2. BOOL CComboCompletion::PreTranslateMessage(MSG* pMsg)  
  3. {  
  4.     if (pMsg->message == WM_CHAR)  
  5.     {  
  6.         m_bAutoComplete = TRUE;  
  7.         int nVirtKey = (int) pMsg->wParam;  
  8.         switch(nVirtKey)  
  9.         {  
  10.         case VK_RETURN:  
  11.             {  
  12.               // 回车按下,收起下拉列表  
  13.                 ShowDropDown(FALSE);  
  14.   
  15.               // 设置当前选择列  
  16.                 CString str;  
  17.               GetWindowText(str);  
  18.               SelectString(-1, str);  
  19.               // 这里直接返回,于是组合框的爸爸也无法响应回车了  
  20.               return TRUE;  
  21.             }  
  22.          // 如果是删除操作,则不进行自动完成  
  23.         case VK_DELETE:  
  24.         case VK_BACK:  
  25.             m_bAutoComplete = FALSE;  
  26.         default:  
  27.             break;  
  28.         }  
  29.     }  
  30.     return CComboBox::PreTranslateMessage(pMsg);  
  31. }  

接下来处理编辑事件响应。

注意PostMessage是自动选择的关键!否则下拉框虽然能滚动,但是不会高亮选择项!

原因不是很明确,不过肯定是消息同步和异步处理之间的原因。

 

[cpp] view plaincopy
  1. void CComboCompletion::OnEditUpdate()   
  2. {  
  3.     CString line;               // partial line entered by user  
  4.     CString sMatchedText;       // holds full line from list  
  5.   
  6.     // get the text from the user input  
  7.     GetWindowText(line);  
  8.     int iHiLightStart = line.GetLength();  
  9.   
  10.     // if the line is empty  
  11.     if(line.GetLength() == 0)   
  12.     {  
  13.          // 关闭下拉框  
  14.          ShowDropDown(FALSE);  
  15.   
  16.         // empty the selection  
  17.         SetWindowText(_T(""));     
  18.         m_bAutoComplete = true;  
  19.         return;  
  20.     }  
  21.     // 这里处理删除操作的逻辑  
  22.     if(!m_bAutoComplete)  
  23.     {  
  24.        m_bAutoComplete = true;  
  25.         return;  
  26.     }  
  27.     // 开始匹配用户输入  
  28.     int m_iSelectedRow = FindString(-1, line);  
  29.   
  30.     if(m_iSelectedRow >= 0)  
  31.     {  
  32.         // 打开下拉框  
  33.         ShowDropDown(TRUE);  
  34.   
  35.         // 注意这里一定要使用postmessage以保证下拉框的选项被选中!  
  36.         PostMessage(CB_SETCURSEL, m_iSelectedRow, 0);  
  37.   
  38.     }  
  39.     // 接下来处理匹配失败  
  40.     else   
  41.     {  
  42.        ShowDropDown(FALSE);  
  43.        SetWindowText(line);  
  44.     }  
  45.     // 最后我们要高亮自动匹配的部分,以方便用户继续编辑,同样的要用异步消息发送  
  46.     PostMessage(CB_SETEDITSEL, 0, MAKELPARAM(iHiLightStart, -1));  
  47. }  

基本就差不多了,你会发现一个bug,就是自动提示的时候打开下拉框鼠标不见了!

嘿嘿。。。这就是我最开始之所以响应CBN_DROPDOWN消息的原因,这里得做个补救措施:

[cpp] view plaincopy
  1. void CComboCompletion::OnDropdown()  
  2. {  
  3.     SetCursor(LoadCursor(NULL, IDC_ARROW));  
  4. }  

现在效果出来了,貌似比较专业...下图:

效果图

如果是CComboBoxEx则麻烦一点,你需要自己实现排序,插入,搜索字符串的操作。

然而原理则是一样的。

0 0
原创粉丝点击