现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

ComboBox的高级处理

2013-11-28 00:06 工业·编程 ⁄ 共 2417字 ⁄ 字号 暂无评论

  我承认文章的标题有哗众取宠之嫌,所谓高级处理只不过是对于ComboBox的edit和listbox两个子控件子类化的一个途径。ComboBox我想大家还是了解的,而且其应用场合也比较多,对其特殊定制的需求也就相应的会比较多。ComboBox 中文名叫组合框,MSDN中有对其有的详细介绍http://msdn.microsoft.com/zh-cn/library/12h9x0ch(v=VS.71).aspx,所谓组合就是这个控件其实包含着两个子控件,其一是一个listbox,另外一个根据风格不同可能是静态控件或者是edit,MSDN中原文如下:

A combo box consists of a list box combined with either a static control or edit control. The list-box portion of the control may be displayed at all times or may only drop down when the user selects the drop-down arrow next to the control.

关于更具体的介绍朋友们可以从上面提到的链接详细了解。

    具体应用的时候我们往往不能满足于MFC提供的标准功能,这种情况下我们一般会对控件进行重载定制,对于ComboBox自然也不例外。不过ComboBox略显复杂,它本身还包括子控件,要想完全重载就要对这些子控件同样进行定制。有经验的朋友一定知道这个时候我们需要对这些子控件进行子类化,用我们自己的类去代替。微软同样为我们想到了这一点,在上文提到的链接中介绍说如果要重载ComboBox可以通过一篇文章《How to subclass CListBox and CEdit inside of CComboBox》介绍的方法来实现。这篇文章用的方法是通过OnCtlColor来实现对子控件的子类化的,应该说这个方法很巧妙但并不优雅,而且文章中也提到这个方法必须在ComboBox至少绘制一次的基础上才能起作用,对于一些要求在这之前就要实现替换的需求并不适用,文章相关原文如下:

Note that for subclassing to occur, the dialog box must be painted at least once. There are cases when the dialog box doesn't paint at all (for example, closing the dialog box before it is displayed, hidden dialog boxes). This method may not be suitable when access to the subclassed windows are needed in these cases.

    那么有什么更好的方法实现ComboBox对其子控件的子类化么,本文就是要解决这个问题。要实现子类化其实只要解决一个问题,那就是过去要子类化的控件的句柄。我们知道ComboBox的信息都封装到了COMBOBOXINFO这个结构中,通过ComboBox的成员函数GetComboBoxInfo即可获取这些信息。看一下这个结构的定义,

[cpp] view plaincopy

  1. /*
  2. * Combobox information
  3. */
  4. typedef struct tagCOMBOBOXINFO 
  5. DWORD cbSize; 
  6.     RECT rcItem; 
  7.     RECT rcButton; 
  8. DWORD stateButton; 
  9. HWND hwndCombo; 
  10. HWND hwndItem; 
  11. HWND hwndList; 
  12. } COMBOBOXINFO, *PCOMBOBOXINFO, *LPCOMBOBOXINFO; 

我们发现hwndItem和hwndList应该就是我们想要的。然后我们要为子类化选择一个合适的时间,对于控件来说在PreSubclassWindow函数中处理再合适不过了。这样我们就很好的解决了子类化的途径和时机的问题,动手试一下吧,我重载重载了CComboBox做了测试,为了验证子类化是否成功我没有对ComboBox进行初始化,而是通过子类化的新控件完成的,核心代码如下:

[cpp] view plaincopy

  1. void CExComboBox::PreSubclassWindow() 
  2.     CComboBox::PreSubclassWindow();  
  3.     COMBOBOXINFO    comboInfo;  
  4. //获取控件信息
  5.     comboInfo.cbSize = sizeof(COMBOBOXINFO); 
  6.     GetComboBoxInfo(&comboInfo);  
  7. //子类化编辑框
  8. if(comboInfo.hwndItem != NULL) 
  9.     { 
  10.         m_editReplace.SubclassWindow(comboInfo.hwndItem); 
  11.         m_editReplace.SetWindowText(_T("编辑框已被子类化")); 
  12.     }  
  13. //子类化列表框
  14. if(comboInfo.hwndList != NULL) 
  15.     { 
  16.         m_listboxReplace.SubclassWindow(comboInfo.hwndList); 
  17.         m_listboxReplace.AddString(_T("列表框已被子类化")); 
  18.     } 

    运行程序成功实现目的。我整理了一个小例子,有兴趣的朋友可以下载研究一下,不过大家也能看得出来,功能和实现都比较简单,所以其实这个实例的价值也不是很大。

    个人认为这个方案相对来说比较合理,对于动态创建的控件可通过OnCreate函数来完成子类化。找到了合理的子类化途径我们也就可以更好的对ComboBox做自绘和扩展,以实现更加丰富的功能。

给我留言

留言无头像?