superclass
superclass是一种生成新的窗口类的方法。它的中心思想是依靠现有的窗口类,克隆出另一个窗口类。被克隆的类可以是Windows预定义的窗口类,这些预定义的窗口类有按钮或下拉框控制等等。也可以是一般的类。克隆的窗口类使用被克隆的类(基类)的窗口消息处理函数。
克隆类可以有自己的窗口消息处理函数,也可以使用基类的窗口处理函数。
需要注意的是,superclass是在注册窗口类时就改变了窗口的行为。即通过指定基类的窗口函数或是自己定义的窗口函数。这与后面讲到的subclass是不同的。后者是在窗口创建完毕后,通过修改窗口函数的地址等改变一个窗口的行为的。
请看示例(摘自MSDN):
该类实现一个按钮,在点击它时,会有响声。
该类的消息映射处理WM_LBUTTONDOWN消息。其它的消息由Windows缺省窗口函数处理。
在消息映射前面,有一个宏--DECLARE_WND_SUPERCLASS()。它的作用就是申明BeepButton是Button的一个superclass。
分析一下这个宏:
这个宏定义了一个静态函数GetWndClassInfo()。这个函数返回了一个窗口类注册时用到的数据结构CWndClassInfo。该结构的详细定义如下:
这个结构调用了一个静态函数AtlModuleRegisterWndClassInfoA(&_Module, this, p);。这个函数的用处就是注册窗口类。
它指定了WndClassName是OrigWdClassName的superclass。
subclass
subclass是普遍采用的一种扩展窗口功能的方法。它的大致原理如下。
在一个窗口创建完了之后,将该窗口的窗口函数替换成新的窗口消息处理函数。这个新的窗口函数可以对某些需要处理的特定的消息进行处理,然后再将处理传给原来的窗口函数。
注意它与superclass的区别。
Superclass是以一个类为原版,进行克隆。既在注册新的窗口类时,使用的是基类窗口的窗口函数。
而subclass是在某一个窗口注册并创建后,通过修改该窗口的窗口消息函数的地址而实现的。它是针对窗口实例。
看一个从MSDN来的例子:
这里定义了一个只接收数字的编辑控件。即通过消息映射,定义了一个特殊的消息处理逻辑。
然后,我们使用CWindowImplT. SubclassWindow()来subclass一个编辑控件。
上述代码中,ed.SubclassWindow( GetDlgItem( IDC_EDIT1 ) )语句是对IDC_EDIT1这个编辑控件进行subclass。该语句实际上是替换了编辑控件的窗口函数。
由于SubClassWindows()实现的机制和ATL封装窗口函数的机制一样,我们会在后面介绍ATL是怎么实现它的。
superclass是一种生成新的窗口类的方法。它的中心思想是依靠现有的窗口类,克隆出另一个窗口类。被克隆的类可以是Windows预定义的窗口类,这些预定义的窗口类有按钮或下拉框控制等等。也可以是一般的类。克隆的窗口类使用被克隆的类(基类)的窗口消息处理函数。
克隆类可以有自己的窗口消息处理函数,也可以使用基类的窗口处理函数。
需要注意的是,superclass是在注册窗口类时就改变了窗口的行为。即通过指定基类的窗口函数或是自己定义的窗口函数。这与后面讲到的subclass是不同的。后者是在窗口创建完毕后,通过修改窗口函数的地址等改变一个窗口的行为的。
请看示例(摘自MSDN):
class CBeepButton: public CWindowImpl< CBeepButton > { public: DECLARE_WND_SUPERCLASS( _T("BeepButton"), _T("Button") ) BEGIN_MSG_MAP( CBeepButton ) MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLButtonDown ) END_MSG_MAP() LRESULT OnLButtonDown( UINT, WPARAM, LPARAM, BOOL& bHandled ) { MessageBeep( MB_ICONASTERISK ); bHandled = FALSE; // alternatively: DefWindowProc() return 0; } }; // CBeepButton |
该类实现一个按钮,在点击它时,会有响声。
该类的消息映射处理WM_LBUTTONDOWN消息。其它的消息由Windows缺省窗口函数处理。
在消息映射前面,有一个宏--DECLARE_WND_SUPERCLASS()。它的作用就是申明BeepButton是Button的一个superclass。
分析一下这个宏:
#define DECLARE_WND_SUPERCLASS(WndClassName, OrigWndClassName) / static CWndClassInfo& GetWndClassInfo() / { / static CWndClassInfo wc = / { / { sizeof(WNDCLASSEX), 0, StartWindowProc, / 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, / OrigWndClassName, NULL, NULL, TRUE, 0, _T("") / }; / return wc; / } |
这个宏定义了一个静态函数GetWndClassInfo()。这个函数返回了一个窗口类注册时用到的数据结构CWndClassInfo。该结构的详细定义如下:
struct _ATL_WNDCLASSINFOA { WNDCLASSEXA m_wc; LPCSTR m_lpszOrigName; WNDPROC pWndProc; LPCSTR m_lpszCursorID; BOOL m_bSystemCursor; ATOM m_atom; CHAR m_szAutoName[13]; ATOM Register(WNDPROC* p) { return AtlModuleRegisterWndClassInfoA(&_Module, this, p); } }; struct _ATL_WNDCLASSINFOW { … … { return AtlModuleRegisterWndClassInfoW(&_Module, this, p); } }; typedef _ATL_WNDCLASSINFOA CWndClassInfoA; typedef _ATL_WNDCLASSINFOW CWndClassInfoW; #ifdef UNICODE #define CWndClassInfo CWndClassInfoW #else #define CWndClassInfo CWndClassInfoA #endif |
这个结构调用了一个静态函数AtlModuleRegisterWndClassInfoA(&_Module, this, p);。这个函数的用处就是注册窗口类。
它指定了WndClassName是OrigWdClassName的superclass。
subclass
subclass是普遍采用的一种扩展窗口功能的方法。它的大致原理如下。
在一个窗口创建完了之后,将该窗口的窗口函数替换成新的窗口消息处理函数。这个新的窗口函数可以对某些需要处理的特定的消息进行处理,然后再将处理传给原来的窗口函数。
注意它与superclass的区别。
Superclass是以一个类为原版,进行克隆。既在注册新的窗口类时,使用的是基类窗口的窗口函数。
而subclass是在某一个窗口注册并创建后,通过修改该窗口的窗口消息函数的地址而实现的。它是针对窗口实例。
看一个从MSDN来的例子:
class CNoNumEdit: public CWindowImpl< CNoNumEdit > { BEGIN_MSG_MAP( CNoNumEdit ) MESSAGE_HANDLER( WM_CHAR, OnChar ) END_MSG_MAP() LRESULT OnChar( UINT, WPARAM wParam, LPARAM, BOOL& bHandled ) { TCHAR ch = wParam; if( _T('0') <= ch && ch <= _T('9') ) MessageBeep( 0 ); else bHandled = FALSE; return 0; } }; |
这里定义了一个只接收数字的编辑控件。即通过消息映射,定义了一个特殊的消息处理逻辑。
然后,我们使用CWindowImplT. SubclassWindow()来subclass一个编辑控件。
class CMyDialog: public CDialogImpl<CMyDialog> { public: enum { IDD = IDD_DIALOG1 }; BEGIN_MSG_MAP( CMyDialog ) MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog ) END_MSG_MAP() LRESULT OnInitDialog( UINT, WPARAM, LPARAM, BOOL& ) { ed.SubclassWindow( GetDlgItem( IDC_EDIT1 ) ); return 0; } CNoNumEdit ed; }; |
上述代码中,ed.SubclassWindow( GetDlgItem( IDC_EDIT1 ) )语句是对IDC_EDIT1这个编辑控件进行subclass。该语句实际上是替换了编辑控件的窗口函数。
由于SubClassWindows()实现的机制和ATL封装窗口函数的机制一样,我们会在后面介绍ATL是怎么实现它的。