第十一章 WTL 对 DDX 的支持
WTL 还复制了 MFC 的另外一个特性就是动态数据交换(DDX). DDX 所完成的工作就是在窗口对象的数据成员变量与窗口的子控件之间来回传递数据. WTL 的 CWinDataExchange 类提供饿 DDX 的支持, 而相关的一组宏定义则实现了 DoDataExhange 方法.
// atlddx.h
template <class T> class CWinDataExchange {
public:
// Data exchange method - override in your derived class
BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT
/*nCtlID*/ = (UINT)-1)
{
// this one should never be called, override it in
// your derived class by implementing DDX map
ATLASSERT(FALSE);
return FALSE;
}
…
};
任何需要使用 DDX 的类只需要从 CWinDataExchange 派生并提供 DoDataExchange 的实现即可. 这个方法的实现最简单的方式就是使用 DDX_MAP 宏, 并给定与客户区上子控件相对应的入口, 例如
class CStringDialog :
public CDialogImpl<CStringDialog>,
public CWinDataExchange<CStringDialog>
{
public:
CStringDialog() { *m_sz = 0; }
enum { IDD = IDD_STRING };
BEGIN_MSG_MAP(CStringDialog)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
END_MSG_MAP()
BEGIN_DDX_MAP(CMainDlg)
DDX_TEXT(IDC_STRING, m_sz)
END_DDX_MAP()
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) {
DoDataExchange(FALSE); // Populate the controls
return 0;
}
LRESULT OnOK(WORD, WORD wID, HWND, BOOL&) {
DoDataExchange(TRUE); // Populate the data members
EndDialog(wID);
return 0L;
}
LRESULT OnCancel(WORD, WORD wID, HWND, BOOL&) {
EndDialog(wID);
return 0L;
}
public:
enum { MAX_STRING = 128 };
char m_sz[MAX_STRING+1];
};
CStringDialog 类从 CWinDataExhange 派生并包含了一个简单的编辑控件. 对话框类在 WM_INITDIALOG 消息映射函数中调用 DoDataExchange(FALSE)把 m_sz 变量的值传递给其对应的控件. 而在 OK 按钮触发的消息映射函数中调用 DoDataExchange(TRUE) 来同步对话框数据成员 m_sz 的值与相应编辑控件的状态, 也就是把编辑框所拥有的值传递给数据成员变量. 这与 MFC 中 DDX 的实现和使用非常的相似.
LRESULT CMainFrame::OnFileTitle(WORD,WORD wID, HWND,BOOL&) {
CStringDialog dlg;
GetWindowText(dlg.m_sz, dlg.MAX_STRING);
if( dlg.DoModal() == IDOK ) SetWindowText(dlg.m_sz);
return 0L;
}
除了文本之外, WTL 的 DDX 还支持有符号和无符号整数和浮点数, 也支持控件如 radio buttons 和 checkboxes. Table3 给出了atlddx.h 中定义的 DDX 宏
Table 3: WTL’s DDX Macros
Macro Purpose
DDX_TEXT(nID, var) 使控件的文本内容与 CString, CComBSTR 或者 LPTSTR 类型的
成员变量关联
DDX_TEXT_LEN(nID, var, len) 与 DDX_TEXT 相同同时指定文本长度.
DDX_INT(nID, var) 将子控件中用户键入的数值与整型成员变量关联
DDX_INT_RANGE(nID, var, min, max) 与 DDX_INT 相同同时指定数值范围.
DDX_UINT(nID, var) 与 DDX_INT 相同, 适用于无符号整型
DDX_UINT_RANGE(nID, var, min, max) 与 DDX_INT_RANGE 相同适用于无符号整型.
DDX_FLOAT(nID, var) 与 DDX_INT 相同适用于浮点数.
DDX_FLOAT_RANGE(nID, var, min, max) 与 DDX_INT_RANGE 相同适用于浮点数
DDX_CONTROL(nID, obj) DDX_CONTROL 宏子类化一个控件, 此控件由宏参数 obj 指定,
正因为如此数据成员必须是CWindowImpl 的派生类或者至少应该
有SubclassWindow 成员函数.
DDX_CHECK(nID, var) 把 var 变量设置为 nID 对应控件的状态值
DDX_RADIO(nID, var) 在单选按钮组与整型成员变量之间进行数据传输
(译者注:docx 文档在 OpenOffice 下编辑, 表格复制到网页之后没了表格, 仅仅复制了表格内容, 没找到解决办法, 索性不要表格了 ^_^ )
与 MFC 相比, WTL 的 DDX 并不是自动进行的, 程序员需要手动调用 DoDataExchange 启动传递过程. 这使得你可以精确控制何时进行, 具有相当的灵活性. 当然你也可以在调用 DoDataExchange 时给出控件 ID, 这将只针对此控件启动数据传递过程.
WTL Wizardry
To be continued...