·ATL 方式 3 - 子类化(Subclassing)
第三种方法创建一个CWindowImpl派生类并用它子类化一个控件。这和第二种方法有些相似,只是消息处理放在CWindowImpl类内部而不是对话框类中。
ControlMania1使用这种方法子类化主对话框的About按钮。下面是CButtonImpl类,他从CWindowImpl类派生,处理WM_SETCURSOR消息:
class CButtonImpl : public CWindowImpl<CButtonImpl, CButton> { BEGIN_MSG_MAP_EX(CButtonImpl) MSG_WM_SETCURSOR(OnSetCursor) END_MSG_MAP()
LRESULT OnSetCursor(HWND hwndCtrl, UINT uHitTest, UINT uMouseMsg) { static HCURSOR hcur = LoadCursor ( NULL, IDC_SIZEALL );
if ( NULL != hcur ) { SetCursor ( hcur ); return TRUE; } else { SetMsgHandled(false); return FALSE; } } }; |
接着在主对话框声明一个CButtonImpl成员变量:
class CMainDlg : public CDialogImpl<CMainDlg> { // ... protected: CContainedWindow m_wndOKBtn, m_wndExitBtn; CButtonImpl m_wndAboutBtn; }; |
最后,在OnInitDialog()种子类化About按钮。
LRESULT CMainDlg::OnInitDialog(...) { // ... // Attach CContainedWindows to OK and Exit buttons m_wndOKBtn.SubclassWindow ( GetDlgItem(IDOK) ); m_wndExitBtn.SubclassWindow ( GetDlgItem(IDCANCEL) );
// CButtonImpl: subclass the About button m_wndAboutBtn.SubclassWindow ( GetDlgItem(ID_APP_ABOUT) );
return TRUE; } |
·WTL 方式 - 对话框数据交换(DDX)
WTL的DDX(对话框数据交换)很像MFC,可以使用很简单的方法将变量和控件关联起来。首先,和前面的例子一样你需要从CWindowImpl派生一个新类,这次我们使用一个新类CEditImpl,因为这次我们使用得是Edit控件。你还需要将#include atlddx.h 添加到stdafx.h中,这样就可以使用DDX代码。
要使主对话框支持DDX,需要将CWinDataExchange添加到继承列表中:
class CMainDlg : public CDialogImpl<CMainDlg>, public CWinDataExchange<CMainDlg> { //... }; |
接着在对话框类中添加DDX链,这和MFC的类向导使用的DoDataExchange()函数功能相似。对于不同类型的数据可以使用不同的DDX宏,我们使用DDX_CONTROL用来连接变量和控件,这次我们使用CEditImpl处理WM_CONTEXTMENU消息,使它能够在你右键单控件时做一些事情。
class CEditImpl : public CWindowImpl<CEditImpl, CEdit> { BEGIN_MSG_MAP_EX(CEditImpl) MSG_WM_CONTEXTMENU(OnContextMenu) END_MSG_MAP()
void OnContextMenu ( HWND hwndCtrl, CPoint ptClick ) { MessageBox("Edit control handled WM_CONTEXTMENU"); } };
class CMainDlg : public CDialogImpl<CMainDlg>, public CWinDataExchange<CMainDlg> { //...
BEGIN_DDX_MAP(CMainDlg) DDX_CONTROL(IDC_EDIT, m_wndEdit) END_DDX_MAP()
protected: CContainedWindow m_wndOKBtn, m_wndExitBtn; CButtonImpl m_wndAboutBtn; CEditImpl m_wndEdit; }; |
最后,在OnInitDialog()中调用DoDataExchange()函数,这个函数是继承自CWinDataExchange。DoDataExchange()第一次被调用时完成相关控件的子类化工作,所以在这个例子中,DoDataExchange()子类化ID为IDC_EDIT的控件,将其与m_wndEdit建立关联。
LRESULT CMainDlg::OnInitDialog(...) { // ... // Attach CContainedWindows to OK and Exit buttons m_wndOKBtn.SubclassWindow ( GetDlgItem(IDOK) ); m_wndExitBtn.SubclassWindow ( GetDlgItem(IDCANCEL) );
// CButtonImpl: subclass the About button m_wndAboutBtn.SubclassWindow ( GetDlgItem(ID_APP_ABOUT) );
// First DDX call, hooks up variables to controls. DoDataExchange(false);
return TRUE; } |
DoDataExchange()的参数与MFC的UpdateData()函数的参数意义相同,我会在下一节详细介绍。
现在运行ControlMania1程序,可以看到子类化的效果。鼠标右键单击编辑框将弹出消息框,当鼠标通过按钮上时鼠标形状会改变。
|