http://www.cppblog.com/qinqing1984/archive/2010/06/14/117872.html
WTL是窗口模板库(Windows Library Template)的简称,是一套轻量级C++ GUI库,因为它使用了C++模板封装了窗口界面操作API和消息映射处理,它扩展了ATL中的UI窗口部分,并支持如下更多的功能特性:
(1) 对话框和通用控件:包括对话框数据交换(DDX),子类化,控件消息通知与反射等
(2) 工具栏和状态栏:包括工具条UI状态更新,多窗格状态条及UI状态更新等
(3) 分隔窗口:包括窗格容器,嵌套分隔,特殊绘制等
(4) 属性页和向导:包括属性表,普通属性页,向导属性页等
(5) GDI类等:包括GDI封装类,通用对话框等
(6) 使用ActiveX控件:包括使用控件类,调用控件的方法,控件事件映射处理等
(7) 高级对话框UI类:包括自绘和外观定制类,新控件类,控件UI状态更新,对话框数据验证DDV等
(8) 支持拖放操作:包括拖放接口实现类,最近使用文件列表等
因此综上所述,使用WTL几乎可以实现MFC所能实现的功能与界面,而且生成的执行文件体积更小,不需要动态链接库就可直接快速地执行。下文就上列表(1)中的控件消息通知与反射作下探讨总结,我们知道,根据WIN32窗口原理,一般由父窗口接收其子窗口或控件的通知或命令消息当相关事件发生的时候,在这里,父窗口是消息接收者,子窗口或控件是消息发送者,那么谁是消息处理者呢?实际上由谁来处理消息只是代码上的逻辑,既可以在父窗口的窗口过程回调内处理,也可以在子窗口或控件的窗口过程回调内处理,在哪处理更方便更合理就可在哪处理,如果是在子窗口或控件窗口过程回调内处理,那么就需要作下额外的处理了,这种处理无非就是在父窗口中将消息再反射给发送者,进而则可由发送者处理了。它在WTL实现的方法一般有两种:
(1) 将所需子窗口或控件设计成子类,继承于CWindowImpl模板基类,在该子类内添加消息映射项和消息处理函数,消息映射项用REFLECTED_NOTIFY_XXX或REFLECTED_COMMAND_XXX系列反射宏实现即可,具体使用哪个宏,决定于是否通知或命令消息,及消息对应的ID和通知码。最后在父窗口类消息映射链中添加反射通知宏REFLECT_NOTIFICATIONS()项,这项一般添加在最后。示例代码如下:
(2) 不使用派生类,直接使用ATL中的包含窗口模板类CContainedWindowT,模板参数为子窗口或控件的类名,实例化为父窗口类的成员变量,在父窗口类消息映射中需要添加ALT_MSG_MAP宏来实现消息分派,其参数为分派ID,这个ID为成员变量初始化时指定的常量。最后在父窗口类消息映射链中添加反射通知宏REFLECT_NOTIFICATIONS(),注意ALT_MSG_MAP宏必须在反射通知宏REFLECT_NOTIFICATIONS之后。示例代码如下:
(1) 对话框和通用控件:包括对话框数据交换(DDX),子类化,控件消息通知与反射等
(2) 工具栏和状态栏:包括工具条UI状态更新,多窗格状态条及UI状态更新等
(3) 分隔窗口:包括窗格容器,嵌套分隔,特殊绘制等
(4) 属性页和向导:包括属性表,普通属性页,向导属性页等
(5) GDI类等:包括GDI封装类,通用对话框等
(6) 使用ActiveX控件:包括使用控件类,调用控件的方法,控件事件映射处理等
(7) 高级对话框UI类:包括自绘和外观定制类,新控件类,控件UI状态更新,对话框数据验证DDV等
(8) 支持拖放操作:包括拖放接口实现类,最近使用文件列表等
因此综上所述,使用WTL几乎可以实现MFC所能实现的功能与界面,而且生成的执行文件体积更小,不需要动态链接库就可直接快速地执行。下文就上列表(1)中的控件消息通知与反射作下探讨总结,我们知道,根据WIN32窗口原理,一般由父窗口接收其子窗口或控件的通知或命令消息当相关事件发生的时候,在这里,父窗口是消息接收者,子窗口或控件是消息发送者,那么谁是消息处理者呢?实际上由谁来处理消息只是代码上的逻辑,既可以在父窗口的窗口过程回调内处理,也可以在子窗口或控件的窗口过程回调内处理,在哪处理更方便更合理就可在哪处理,如果是在子窗口或控件窗口过程回调内处理,那么就需要作下额外的处理了,这种处理无非就是在父窗口中将消息再反射给发送者,进而则可由发送者处理了。它在WTL实现的方法一般有两种:
(1) 将所需子窗口或控件设计成子类,继承于CWindowImpl模板基类,在该子类内添加消息映射项和消息处理函数,消息映射项用REFLECTED_NOTIFY_XXX或REFLECTED_COMMAND_XXX系列反射宏实现即可,具体使用哪个宏,决定于是否通知或命令消息,及消息对应的ID和通知码。最后在父窗口类消息映射链中添加反射通知宏REFLECT_NOTIFICATIONS()项,这项一般添加在最后。示例代码如下:
1
class
CFileListViewCtrl
:
public
CWindowImpl
<
CFileListViewCtrl
,
CListViewCtrl
>
2 {
3 protected:
4 BEGIN_MSG_MAP(CFileListViewCtrl)
5 REFLECTED_NOTIFY_CODE_HANDLER_EX(LVN_GETINFOTIP,OnGetInfoTip) //反射通知消息处理宏
6 CHAIN_MSG_MAP(CListViewCtrl)
7 END_MSG_MAP()
8 LRESULT OnGetInfoTip(NMHDR* pNMHDR); //消息响应处理函数
9} ;
图1 派生类消息映射
2 {
3 protected:
4 BEGIN_MSG_MAP(CFileListViewCtrl)
5 REFLECTED_NOTIFY_CODE_HANDLER_EX(LVN_GETINFOTIP,OnGetInfoTip) //反射通知消息处理宏
6 CHAIN_MSG_MAP(CListViewCtrl)
7 END_MSG_MAP()
8 LRESULT OnGetInfoTip(NMHDR* pNMHDR); //消息响应处理函数
9} ;
1
class
COpenFileDlg
:
public
CDialogImpl
<
COpenFileDlg
>
,
public
CWinDataExchange
<
COpenFileDlg
>
2 {
3public:
4 COpenFileDlg();
5 ~COpenFileDlg();
6 enum { IDD = IDD_OPEN_FILE_DLG };
7
8protected:
9 BEGIN_MSG_MAP(COpenFileDlg)
10 MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)
11 REFLECT_NOTIFICATIONS() //消息反射通知宏
12 END_MSG_MAP()
13
14 BEGIN_DDX_MAP(COpenFileDlg)
15 DDX_CONTROL(IDC_LIST_FILE,m_list_File)
16 END_DDX_MAP()
17
18 LRESULT OnInitDialog(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandle);
19 LRESULT OnListViewDblclk(NMHDR* pNMHDR);
20
21private:
22 CFileListViewCtrl m_list_File; //使用派生类实例作为成员变量
23} ;
图2 父窗口类消息映射
2 {
3public:
4 COpenFileDlg();
5 ~COpenFileDlg();
6 enum { IDD = IDD_OPEN_FILE_DLG };
7
8protected:
9 BEGIN_MSG_MAP(COpenFileDlg)
10 MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)
11 REFLECT_NOTIFICATIONS() //消息反射通知宏
12 END_MSG_MAP()
13
14 BEGIN_DDX_MAP(COpenFileDlg)
15 DDX_CONTROL(IDC_LIST_FILE,m_list_File)
16 END_DDX_MAP()
17
18 LRESULT OnInitDialog(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandle);
19 LRESULT OnListViewDblclk(NMHDR* pNMHDR);
20
21private:
22 CFileListViewCtrl m_list_File; //使用派生类实例作为成员变量
23} ;
(2) 不使用派生类,直接使用ATL中的包含窗口模板类CContainedWindowT,模板参数为子窗口或控件的类名,实例化为父窗口类的成员变量,在父窗口类消息映射中需要添加ALT_MSG_MAP宏来实现消息分派,其参数为分派ID,这个ID为成员变量初始化时指定的常量。最后在父窗口类消息映射链中添加反射通知宏REFLECT_NOTIFICATIONS(),注意ALT_MSG_MAP宏必须在反射通知宏REFLECT_NOTIFICATIONS之后。示例代码如下:
1
class
COpenFileDlg
:
public
CDialogImpl
<
COpenFileDlg
>
,
public
CWinDataExchange
<
COpenFileDlg
>
2 {
3 public:
4 COpenFileDlg();
5 ~COpenFileDlg();
6 enum { IDD = IDD_OPEN_FILE_DLG };
7
8 protected:
9 BEGIN_MSG_MAP(COpenFileDlg)
10 MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)
11 REFLECT_NOTIFICATIONS() // 消息反射通知宏
12 ALT_MSG_MAP(1) // 消息分派宏
13 REFLECTED_NOTIFY_CODE_HANDLER_EX(NM_DBLCLK,OnListViewDblclk) // 反射通知消息处理宏
14 END_MSG_MAP()
15
16 BEGIN_DDX_MAP(COpenFileDlg)
17 DDX_CONTROL(IDC_LIST_FILE,m_list_File)
18 END_DDX_MAP()
19
20 LRESULT OnInitDialog(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandle);
21 LRESULT OnListViewDblclk(NMHDR* pNMHDR); //消息响应处理函数
22 private:
23 CContainedWindowT<CListViewCtrl> m_list_File; // 实例化包含窗口模板类作为成员变量
24 } ;
图3 父窗口类消息映射
2 {
3 public:
4 COpenFileDlg();
5 ~COpenFileDlg();
6 enum { IDD = IDD_OPEN_FILE_DLG };
7
8 protected:
9 BEGIN_MSG_MAP(COpenFileDlg)
10 MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)
11 REFLECT_NOTIFICATIONS() // 消息反射通知宏
12 ALT_MSG_MAP(1) // 消息分派宏
13 REFLECTED_NOTIFY_CODE_HANDLER_EX(NM_DBLCLK,OnListViewDblclk) // 反射通知消息处理宏
14 END_MSG_MAP()
15
16 BEGIN_DDX_MAP(COpenFileDlg)
17 DDX_CONTROL(IDC_LIST_FILE,m_list_File)
18 END_DDX_MAP()
19
20 LRESULT OnInitDialog(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandle);
21 LRESULT OnListViewDblclk(NMHDR* pNMHDR); //消息响应处理函数
22 private:
23 CContainedWindowT<CListViewCtrl> m_list_File; // 实例化包含窗口模板类作为成员变量
24 } ;
1
COpenFileDlg
::
COpenFileDlg():
2 m_list_File( this , 1 ) // 指定消息分派ID为1
3 {
4}
图4 构造函数内初始化
2 m_list_File( this , 1 ) // 指定消息分派ID为1
3 {
4}