在基於對話方塊的程式中,有一個任務是改變編輯框控制項的背景,怎麼辦?
實現思路如下,子控制項要繪製時會向父類(這裡是主視窗)發送WM_CTLCOLOR
訊息,在父類中(這裡是主視窗)響應WM_CTLCOLOR,根據訊息傳遞過來的
參數進行相應的操作,具體代碼如下:
CBrush m_brush;
m_brush.CreateSolidBrush(RGB(0, 0, 255));
HBRUSH CMy112Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);if (pWnd->GetDlgCtrlID() == IDC_EDIT1){pDC->SetBkMode(TRANSPARENT);return m_brush;}return hbr;}
代碼解釋如下:在主對話方塊類CMy112Dlg中定義一個成員變數m_brush,並在主對話
框類中的建構函式中進行初始化。然後為父類編寫WM_CTLCOLOR,在訊息響應中判斷
控制項是否為要設定的編輯框控制項(要設定的編輯框控制項ID為IDC_EDIT1)將背景模式設
置為透明,並設定控制項背景為藍色。
這和訊息反射有什麼關係呢?上述代碼有問題嗎?上述方法也不失為一種好方法,但從
軟體工程角度看還有一些缺憾,子類控制項的訊息都要父類去處理,這樣就會導致父類
中的代碼臃腫,而子類無事可做。另一方面,如果其它的工程要用到類似功能,怎麼辦?
只好把上述函數代碼拷貝到另外工程中,並進行稍微修改。
MFC4.0開始有瞭解決此問題的一種新方法:訊息反射,以上面為例,子控制項要繪製時,
會向父類發送要繪製的訊息,父類收到訊息後,首先反射(再發給)給子控制項,看子控制項
是否對此訊息做了處理,如果做了處理,父類將不再處理。如果子控制項沒有處理,則
父類對子控制項發送的訊息做處理。
再看一下上面例子的另一種方法:訊息反射法
為工程添加一處新類CYellowEdit,此類從MFC的CEdit類派生,為類添加三個成員變數
COLORREF m_clrText;COLORREF m_clrBkgnd;CBrush m_brBkgnd;
分別是文本顏色,背景色,畫刷,在CYellowEdit類建構函式中進行初始化
CYellowEdit::CYellowEdit(){m_clrText = RGB(0, 0, 0);m_clrBkgnd = RGB(255, 255, 0);m_brBkgnd.CreateSolidBrush(m_clrBkgnd);}
為CYellowEdit類添加反射函數(訊息前面帶有=的是反射訊息,本例中為=WM_CTRLCOLR,
HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor) {pDC->SetTextColor(m_clrText); // 文本顏色pDC->SetBkColor(m_clrBkgnd); // 背景色return m_brBkgnd; // 控制項背景}
在主對話方塊上再添加一個編輯框,並為之關聯變數,關聯變數類型為CYelloEdit,運行程式可
以看到編輯框的背景已變成黃色了。
這就是訊息反射的一個用處,使用訊息反射和不使用訊息反射這兩個例子有什麼區別呢?個
人認為最大的區別就是代碼的可重用性,使用訊息反射後,如果碰到類似應用,直接將
CYellowEdit拷貝到其它工程直接應用,不需要修改代碼。
上述例子在MSDN中有詳細介紹,在MSDN中主題為:ON_NOTIFY_REFLECT,
裡面有一篇
TN062: Message Reflection for Windows Controls
的文章專門講述了訊息反射。網上也有不少這方面的文章,但基本上都是參考MSDN翻譯的,
下面給出幾個訊息反射資料的博文地址
1 http://blog.csdn.net/gao_zilai/article/details/7417690
2 http://blog.csdn.net/cay22/article/details/6171616
3 http://bbs.ednchina.com/BLOG_ARTICLE_1926378.HTM