CComboBox的探究。花了几个小时写这些东东,希望对初学者有所帮助。 阅读此文前请注意:文中是以FormView来探究整个过程,如果读者使用的是基于对话框的应用程序,则视情况更改代码内容,不影响阅读。程序设计中组合框使用相当多,但对于组合框的结构,大部分程序设计者只知其大概,即一般的组合框是由 Edit框+ListBox框组合而成。实际情况是这样吗? 如果上面观点正确,那么就能够通过Edit指针和ListBox指针直接操作CComboBox控件了,可如何获得组合框的Edit指针和ListBox指针呢,Edit框和ListBox框在CComboBox中是怎样结合在一起的呢? 本文将根据此一要点,进一步解析组合框的结构。在开始探究之前,我们建立一对话框应用程序,在其上放几个ComboBox控件(IDC_COMBO1~IDC_COMBO7吧),放多个的目的是为了便于比较观察。然后在控件的Data属性中增加一些内容,以免点击下拉箭头空空如也。程序设计中有可能会遇到更改控件颜色的问题。对于一般的控件,可以在对话框的WM_CTLCOLOR消息中设置,我们也以此方法做下实验。相关代码如下:<1>.HBRUSH CFormVView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);static CBrush br(RGB(255, 0, 0)); //构造一个红色画刷对像,将其背景用红色填充。静态可以避免对像失效。if(pWnd->GetDlgCtrlID() == IDC_COMBO1 ) //如果目前画的控件是IDC_COMBO1,即组合框,则将文字背景色改成红色。{ pDC->SetBkColor(RGB(255, 0, 0));pDC->SetBkMode(TRANSPARENT); //设置成透明色,以免背景前景不协调。return br; //返回我们自己的画刷,让系统画去吧。由于CBrush有重载HBRUSH运算符,所以 //我偷下懒,直接写成return br;}return hbr;}以上设置完毕,编译,运行,却发现并非想像那样整个框呈现红色背景,而是仅仅在Edit框周围产生一个红色的矩形,Edit框内部仍然是白色的。点击下拉箭头,下拉框中连个红色的矩形框都没有了,怎么回事?哦,想起来了,想起来了,因为Edit框会把组合框给盖住,但没有全部盖住,所以,Edit框外边会有一个红色的矩形,但内部还是Edit的颜色,即白色。ListBox框根本就没有机会绘制红色边框,所以整个框仅仅是ListBox的颜色。我们想,Edit和ListBox肯定是CComBox的子控件。根据此想法将程序做下修改。如下:<2>.HBRUSH CFormVView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);static CBrush br(RGB(255, 0, 0)); //构造一个红色画刷对像,将其背景用红色填充。静态可以避免对像失效。if(pWnd->GetDlgCtrlID() == IDC_COMBO1 || //如果目前画的控件是IDC_COMBO1,即组合框,则将文字背景色改成组色。 pWnd->GetParent()->GetDlgCtrlID() == IDC_COMBO1) //嘿嘿,如果目前所画的控件的父窗口是ComboBox框,那么也让它返回红色画刷。{ pDC->SetBkColor(RGB(255, 0, 0)); pDC->SetBkMode(TRANSPARENT); //设置成透明色,以免背景前景不协调。return br; //返回我们自己的画刷,让系统画去吧。由于CBrush有重载HBRUSH运算符,所以 //我偷下懒,直接写成return br;}return hbr;}带着疑惑并激动的心编译,运行,哈哈,果然如此也。成功了成功了。赶紧点击下拉箭头,看看奇迹的发生。结果 ~!@#$%^&*, 怎么回事。困惑,同样的ComboBox, 同样的Edit, 同样的CListBox, 为什么CListBox不改变颜色呢? 难道CListBox无法使用此方法改变颜色吗? 好,我先试试。在对话框上加一个Listbox,按照上述改变控件颜色的方法,运行, 红色的ListBox映入眼睑,可以改变呀, 但但ComboBox中的ListBox为什么改变不了呢? 又一次困惑。别着急,先把程序改成如下:<3>.HBRUSH CFormVView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);static CBrush br(RGB(255, 0, 0)); //构造一个红色画刷对像,将其背景用红色填充。静态可以避免对像失效。if(pWnd->GetParent()->GetDlgCtrlID() == IDC_COMBO1) //嘿嘿,如果目前所画的控件的父窗口是ComboBox框,那么也让它返回红色画刷。{ TRACE1("%d \n", pWnd->GetDlgCtrlID()); //没其它目的,我就是想看看改变颜色的ComboBox的子窗口的ID。 pDC->SetBkColor(RGB(255, 0, 0)); pDC->SetBkMode(TRANSPARENT); //设置成透明色,以免背景前景不协调。return br; //返回我们自己的画刷,让系统画去吧。由于CBrush有重载HBRUSH运算符,所以 //我偷下懒,直接写成return br;}return hbr;}按F5运行, 因为TRACE1只有在调试模式下才会输出到输出窗口中。然后观察值,结果得出的全部是1001,并没有其它值,而我的IDC_COMBO1是1002。好,我再改,将if(pWnd->GetParent()->GetDlgCtrlID() == IDC_COMBO1)改为if(pWnd->GetDlgCtrlID() == 1001), 再次编译,运行,可以看到所有的组合框中Edit框中颜色均变成红色,这说明一个问题:CComboBox控件中的确包含一个Edit子控件,而且此控件的ID是1001。为了验证这句话是正确的,我们在对话框上放一按钮控件IDC_BUTTON1,在其响应函数中增加如下代码。<4>.void CFormVView::OnButton1() {CComboBox* pCom = (CComboBox *)GetDlgItem(IDC_COMBO1);CEdit *pEdit = (CEdit*)pCom->GetDlgItem(1001);CString str;pEdit->GetWindowText(str);MessageBox(str);}运行,并在IDC_COMBO1组合框中随便输入一串字符, 按下Button1按钮, 正如我们所想,弹出来刚才输入的字符串,那么列表框呢?我们再来看看程序段<2>, 这段程序中能改变组合框中Edit框的颜色却改变不了ListBox框的颜色,说明什么呢? 在对话框中的控件不可能不产生WM_CTLCOLOR呀,那好,我们一个一个的查。将对话框上的控件只留一个组合框IDC_COMBO1, 其它控件全部删除,并将程序改为如下。<5>.HBRUSH CFormVView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: Change any attributes of the DC herestatic CBrush br(RGB(255, 0, 0));if(pWnd->GetDlgCtrlID() != IDC_COMBO1 && pWnd->GetDlgCtrlID() != 1001 ) //把IDC_COMBO1和1001即组合框的Edit的ID屏蔽,看看剩下什么。{TRACE1("%d \n", pWnd->GetDlgCtrlID());pDC->SetBkColor(RGB(255, 0, 0));pDC->SetBkMode(TRANSPARENT);return br;}// TODO: Return a different brush if the default is not desiredreturn hbr;}按F5运行, 在TRACE1("%d \n", pWnd->GetDlgCtrlID())下行设置断点,查看输出窗口,得出59648, 这个是什么,我没定义这个ID呀,莫非是对话框模板的? 打开Resource.h头文件,发现#define IDD_FORMV_FORM 101 显然不是,在Resource.h中查找也没查到。反正它是一个控件,不然怎么能用pWnd->GetDlgCtrlID()这个函数呢? 嗯,有了,查看RuntimeClass的名字,就知道是什么了。于是继续更改上述程序<5>。<6>HBRUSH CFormVView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: Change any attributes of the DC herestatic CBrush br(RGB(255, 0, 0));if(pWnd->GetDlgCtrlID() != IDC_COMBO1 && pWnd->GetDlgCtrlID() != 1001 ){TRACE2("%d %s \n", pWnd->GetDlgCtrlID(), pWnd->GetRuntimeClass()->m_lpszClassName); //除了得到ID,还要得到RuntimeClass的名字。pDC->SetBkColor(RGB(255, 0, 0));pDC->SetBkMode(TRANSPARENT);return br;}// TODO: Return a different brush if the default is not desiredreturn hbr;}再次运行,发现每次在输出窗口中都是得到 59648 CFormVView, 原来59648是CFormVView的ID啊。其实如果你对MFC的框架结构熟悉,就会知道,当前View的ID为AFX_IDW_PANE_FIRST, 它的值是(#define AFX_IDW_PANE_FIRST 0xE900 // first pane (256 max))转换成十进制就是59648。好了,再将这个ID也屏蔽掉,即:<7>HBRUSH CFormVView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: Change any attributes of the DC herestatic CBrush br(RGB(255, 0, 0));if(pWnd->GetDlgCtrlID() != IDC_COMBO1 && pWnd->GetDlgCtrlID() != 1001 && pWnd->GetDlgCtrlID() != AFX_IDW_PANE_FIRST){TRACE2("%d %s \n", pWnd->GetDlgCtrlID(), pWnd->GetRuntimeClass()->m_lpszClassName);pDC->SetBkColor(RGB(255, 0, 0));pDC->SetBkMode(TRANSPARENT);return br;}// TODO: Return a different brush if the default is not desiredreturn hbr;}按F5运行,发现再也得不到TRACE2的东东了,这说明此消息没有其它需要绘制的控件了。再次点击组合框的下拉箭头, 哈哈有了, 输出1000 CWnd, 并且组合框中列表呈现红色,想必这个1000一定是ListBox的控件ID了。为了说明问题,我再改程序,打破沙锅改到底。如下:<8>HBRUSH CFormVView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: Change any attributes of the DC herestatic CBrush br(RGB(255, 0, 0));if(pWnd->GetDlgCtrlID() == 1000 ){TRACE2("%d %s \n", pWnd->GetDlgCtrlID(), pWnd->GetRuntimeClass()->m_lpszClassName);pDC->SetBkColor(RGB(255, 0, 0));pDC->SetBkMode(TRANSPARENT);return br;}// TODO: Return a different brush if the default is not desiredreturn hbr;}然后再添加几个组合框,运行。按下每个组合框的下拉箭头,终于将每个组合框的ListBox都改成了红色的了。可是,还有一个问题没弄明白,那就是运行第<2>个程序的时候为什么没能改变ListBox的颜色呢,我再修改程序跟踪一下。<9>HBRUSH CFormVView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: Change any attributes of the DC herestatic CBrush br(RGB(255, 0, 0));if(pWnd->GetDlgCtrlID() != IDC_COMBO1 && pWnd->GetDlgCtrlID() != 1001 && pWnd->GetDlgCtrlID() != AFX_IDW_PANE_FIRST){CWnd *pWndParent = pWnd->GetParent();TRACE1("%x \n", pWndParent->m_hWnd);pDC->SetBkColor(RGB(255, 0, 0));pDC->SetBkMode(TRANSPARENT);return br;}// TODO: Return a different brush if the default is not desiredreturn hbr;} 这一次的调试是为了得到这个ListBox的父窗口的句柄,然后查看这个父窗口是什么,我的机器得到的结果是:10014。 打开Spy++工具(Tools->Spy++), 在菜单中点击Search->Find Window,在框中输入刚才的结果10014, OK, 结果,天啊,竟然是Desktop, 哈哈哈哈,谜底解开了,原来ComboBox的ListBox不是ComboBox的子窗口, Edit控件才是ComboBox的子窗口。今天先写到这里,如果读者有兴趣,可以做出如下功能。代码<4>中,可以通过CEdit来获得组合框中Edit框的值, 读者可以模拟此段程序,实现使用CListBox类来更改组合框下拉列表的内容。
转载于:https://www.cnblogs.com/zhiweiyouzhishenghuo/archive/2012/06/19/5005524.html