WTL的窗口子类化与超类化
2016-11-02 12:27
344 查看
一.窗口超类化(superclassing)
超类化根据已有的(windows系统中已经注册过的)窗口类,比如“Edit”,”Button”等,复制其WNDCLASS(EX)结构,构造一个新类,并提供额外的功能和行为。
例如,如果需要编写一个只接受数字输入的Edit控件(当用户输入非数字符号时控件发出警告声),可超类化windows内置的Edit控件,新控件的窗口类名为”Number_Only_Edit”,(可以在Spy++工具中看到此窗口类名称):
class CNumberOnlyEdit
:
public CWindowImpl
{
public:
//Superclassing
the "Edit" control in Windows
DECLARE_WND_SUPERCLASS(_T("Number_Only_Edit"),_T("Edit"))
BEGIN_MSG_MAP_EX(CNumberOnlyEdit)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
void OnChar(UINT
nChar, UINT nRepCnt, UINT nFlags)
{
//Only
number or backspace is allowed
if (('0'<=nChar
&& nChar<='9') || (nChar==VK_BACK))
{
//Accept
the default process
SetMsgHandled(FALSE);
}
else
{
::MessageBeep(MB_ICONERROR); //Warning
}
}
};
在窗口或对话框中使用此自定义的控件:
//#define IDC_EDIT_NUMBER_ONLY 123
CRect rc(10,10,300,30);
m_NumberOnlyEdit.Create(
m_hWnd,
rc,
_T("NumberOnlyEdit
Superclassing"),
WS_CHILD|WS_VISIBLE,
NULL,
IDC_EDIT_NUMBER_ONLY);
值得注意的是,在定义CNumberOnlyEdit类时,所指定的基类是CWindowImpl,因此m_NumberOnlyEdit实例只能使用CWindow类的方法,而不能使用CEdit类的函数(操作Edit控件的函数)。如果在代码中要用到CEdit类的函数,可将基类改为:
class CNumberOnlyEdit
:
public CWindowImpl
{
//......
}
这样,就可以使用CEdit类的成员函数操作Edit控件了,例如:
//Get the
count of line in Edit
box
int lineCount = m_NumberOnlyEdit.GetLineCount();
二.窗口子类化(Subclassing)
窗口子类化可以改变一个已有的窗口(通常是对话框控件)的行为,以只接受数字输入的Edit控件为例,在WTL中主要有两种方法实现:
1.如果要将特殊消息处理代码放到单独的模块中,可以自定义一个类:
class CNumberOnlyEdit
:
public CWindowImpl
{
public:
BEGIN_MSG_MAP_EX(CNumberOnlyEdit)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
void OnChar(UINT
nChar, UINT nRepCnt, UINT nFlags)
{
//Only
number or backspace is allowed
if (('0'<=nChar
&& nChar<='9') || (nChar==VK_BACK))
{
//Accept
the default process
SetMsgHandled(FALSE); //or
DefWindowProc();
}
else
{
::MessageBeep(MB_ICONERROR); //Warning
}
}
};
然后与已有的控件关联:
//CNumberOnlyEdit m_NumberOnlyEdit;
m_NumberOnlyEdit.SubclassWindow(GetDlgItem(IDC_EDIT_NUMBER));
m_NumberOnlyEdit.SetWindowText(_T("NumberOnlyEdit
Subclassing"));
int lineCount
= m_NumberOnlyEdit.GetLineCount();
//...
如果使用WTL的DDX功能,则可以很方便的将控件变量与控件ID关联:
class CMainDlg
:
public CDialogImpl,
public CWinDataExchange
{
private:
CNumberOnlyEdit m_NumberOnlyEdit;
public:
enum {
IDD = IDD_MAINDLG };
BEGIN_MSG_MAP_EX(CMainDlg)
MESSAGE_HANDLER(WM_INITDIALOG,
OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnOK)
ALT_MSG_MAP(12)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
BEGIN_DDX_MAP(CMainDlg)
DDX_CONTROL(IDC_EDIT_NUMBER,m_NumberOnlyEdit)
END_DDX_MAP()
public:
CMainDlg()
{
}
public:
LRESULT OnInitDialog(UINT ,
WPARAM , LPARAM ,
BOOL& )
{
//
center the dialog on the screen
CenterWindow();
//
set icons
HICON hIcon = AtlLoadIconImage(IDR_MAINFRAME,
LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON));
SetIcon(hIcon, TRUE);
HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME,
LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));
SetIcon(hIconSmall, FALSE);
DoDataExchange(FALSE);
m_NumberOnlyEdit.SetWindowText(_T("NumberOnlyEdit
Subclassing"));
int lineCount
= m_NumberOnlyEdit.GetLineCount();
return TRUE;
}
void OnChar(UINT
nChar, UINT nRepCnt, UINT nFlags)
{
//Only
number or backspace is allowed
if (('0'<=nChar
&& nChar<='9') || (nChar==VK_BACK))
{
//Accept
the default process
SetMsgHandled(FALSE); //or
DefWindowProc();
}
else
{
::MessageBeep(MB_ICONERROR); //Warning
}
}
//...
};
DDX在内部调用SubclassWindow()来将控件变量和控件ID进行关联。
2.不必自定义个一个单独的类,而是将特殊消息的处理代码放到父窗口(对话框)的消息映射中:
class CMainDlg
:
public CDialogImpl
{
private:
CContainedWindowT m_NumberOnlyEdit;
public:
enum {
IDD = IDD_MAINDLG };
BEGIN_MSG_MAP_EX(CMainDlg)
MESSAGE_HANDLER(WM_INITDIALOG,
OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnOK)
ALT_MSG_MAP(12)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
public:
CMainDlg()
: m_NumberOnlyEdit(this,12)
{
//...
}
public:
LRESULT OnInitDialog(UINT ,
WPARAM , LPARAM ,
BOOL& )
{
//
center the dialog on the screen
CenterWindow();
//
set icons
HICON hIcon = AtlLoadIconImage(IDR_MAINFRAME,
LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON));
SetIcon(hIcon, TRUE);
HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME,
LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));
SetIcon(hIconSmall, FALSE);
//subclassing
an Edit control
m_NumberOnlyEdit.SubclassWindow(GetDlgItem(IDC_EDIT_NUMBER));
m_NumberOnlyEdit.SetWindowText(_T("NumberOnlyEdit
Subclassing"));
int lineCount
= m_NumberOnlyEdit.GetLineCount();
return TRUE;
}
void OnChar(UINT
nChar, UINT nRepCnt, UINT nFlags)
{
//Only
number or backspace is allowed
if (('0'<=nChar
&& nChar<='9') || (nChar==VK_BACK))
{
//Accept
the default process
SetMsgHandled(FALSE); //or
DefWindowProc();
}
else
{
::MessageBeep(MB_ICONERROR); //Warning
}
}
//...
};
其中CContainedWindowT在内部生成了一个新类,并将所有的内部窗口消息都转发给了控件的父窗口(即对话框),因此可以将特殊消息处理代码放在父窗口的消息映射列表中,这样,就没有必要自己单独创建一个新类了。
注意,这种处理方法需要我们制定一个消息映射的分支编号(本例子中为12),这是一个任意选定的编号(父窗口中可能存在多个分支编号,以分别处理各个控件转发过来的消息):
CMainDlg()
: m_NumberOnlyEdit(this,12)
{
//...
}
BEGIN_MSG_MAP_EX(CMainDlg)
//...
ALT_MSG_MAP(12) //Process
message from m_NumberOnlyEdit control
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
三.一些结论
有上可知,窗口子类化可以实现窗口超类化相同的功能,且更加灵活。
如果控件的父窗口为普通窗口或父控件窗口,可以使用窗口超类化;如果父窗口是对话框,需要对对话框模板中已存在的控件行为进行定制,可以使用窗口子类化。
超类化根据已有的(windows系统中已经注册过的)窗口类,比如“Edit”,”Button”等,复制其WNDCLASS(EX)结构,构造一个新类,并提供额外的功能和行为。
例如,如果需要编写一个只接受数字输入的Edit控件(当用户输入非数字符号时控件发出警告声),可超类化windows内置的Edit控件,新控件的窗口类名为”Number_Only_Edit”,(可以在Spy++工具中看到此窗口类名称):
class CNumberOnlyEdit
:
public CWindowImpl
{
public:
//Superclassing
the "Edit" control in Windows
DECLARE_WND_SUPERCLASS(_T("Number_Only_Edit"),_T("Edit"))
BEGIN_MSG_MAP_EX(CNumberOnlyEdit)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
void OnChar(UINT
nChar, UINT nRepCnt, UINT nFlags)
{
//Only
number or backspace is allowed
if (('0'<=nChar
&& nChar<='9') || (nChar==VK_BACK))
{
//Accept
the default process
SetMsgHandled(FALSE);
}
else
{
::MessageBeep(MB_ICONERROR); //Warning
}
}
};
在窗口或对话框中使用此自定义的控件:
//#define IDC_EDIT_NUMBER_ONLY 123
CRect rc(10,10,300,30);
m_NumberOnlyEdit.Create(
m_hWnd,
rc,
_T("NumberOnlyEdit
Superclassing"),
WS_CHILD|WS_VISIBLE,
NULL,
IDC_EDIT_NUMBER_ONLY);
值得注意的是,在定义CNumberOnlyEdit类时,所指定的基类是CWindowImpl,因此m_NumberOnlyEdit实例只能使用CWindow类的方法,而不能使用CEdit类的函数(操作Edit控件的函数)。如果在代码中要用到CEdit类的函数,可将基类改为:
class CNumberOnlyEdit
:
public CWindowImpl
{
//......
}
这样,就可以使用CEdit类的成员函数操作Edit控件了,例如:
//Get the
count of line in Edit
box
int lineCount = m_NumberOnlyEdit.GetLineCount();
二.窗口子类化(Subclassing)
窗口子类化可以改变一个已有的窗口(通常是对话框控件)的行为,以只接受数字输入的Edit控件为例,在WTL中主要有两种方法实现:
1.如果要将特殊消息处理代码放到单独的模块中,可以自定义一个类:
class CNumberOnlyEdit
:
public CWindowImpl
{
public:
BEGIN_MSG_MAP_EX(CNumberOnlyEdit)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
void OnChar(UINT
nChar, UINT nRepCnt, UINT nFlags)
{
//Only
number or backspace is allowed
if (('0'<=nChar
&& nChar<='9') || (nChar==VK_BACK))
{
//Accept
the default process
SetMsgHandled(FALSE); //or
DefWindowProc();
}
else
{
::MessageBeep(MB_ICONERROR); //Warning
}
}
};
然后与已有的控件关联:
//CNumberOnlyEdit m_NumberOnlyEdit;
m_NumberOnlyEdit.SubclassWindow(GetDlgItem(IDC_EDIT_NUMBER));
m_NumberOnlyEdit.SetWindowText(_T("NumberOnlyEdit
Subclassing"));
int lineCount
= m_NumberOnlyEdit.GetLineCount();
//...
如果使用WTL的DDX功能,则可以很方便的将控件变量与控件ID关联:
class CMainDlg
:
public CDialogImpl,
public CWinDataExchange
{
private:
CNumberOnlyEdit m_NumberOnlyEdit;
public:
enum {
IDD = IDD_MAINDLG };
BEGIN_MSG_MAP_EX(CMainDlg)
MESSAGE_HANDLER(WM_INITDIALOG,
OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnOK)
ALT_MSG_MAP(12)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
BEGIN_DDX_MAP(CMainDlg)
DDX_CONTROL(IDC_EDIT_NUMBER,m_NumberOnlyEdit)
END_DDX_MAP()
public:
CMainDlg()
{
}
public:
LRESULT OnInitDialog(UINT ,
WPARAM , LPARAM ,
BOOL& )
{
//
center the dialog on the screen
CenterWindow();
//
set icons
HICON hIcon = AtlLoadIconImage(IDR_MAINFRAME,
LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON));
SetIcon(hIcon, TRUE);
HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME,
LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));
SetIcon(hIconSmall, FALSE);
DoDataExchange(FALSE);
m_NumberOnlyEdit.SetWindowText(_T("NumberOnlyEdit
Subclassing"));
int lineCount
= m_NumberOnlyEdit.GetLineCount();
return TRUE;
}
void OnChar(UINT
nChar, UINT nRepCnt, UINT nFlags)
{
//Only
number or backspace is allowed
if (('0'<=nChar
&& nChar<='9') || (nChar==VK_BACK))
{
//Accept
the default process
SetMsgHandled(FALSE); //or
DefWindowProc();
}
else
{
::MessageBeep(MB_ICONERROR); //Warning
}
}
//...
};
DDX在内部调用SubclassWindow()来将控件变量和控件ID进行关联。
2.不必自定义个一个单独的类,而是将特殊消息的处理代码放到父窗口(对话框)的消息映射中:
class CMainDlg
:
public CDialogImpl
{
private:
CContainedWindowT m_NumberOnlyEdit;
public:
enum {
IDD = IDD_MAINDLG };
BEGIN_MSG_MAP_EX(CMainDlg)
MESSAGE_HANDLER(WM_INITDIALOG,
OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnOK)
ALT_MSG_MAP(12)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
public:
CMainDlg()
: m_NumberOnlyEdit(this,12)
{
//...
}
public:
LRESULT OnInitDialog(UINT ,
WPARAM , LPARAM ,
BOOL& )
{
//
center the dialog on the screen
CenterWindow();
//
set icons
HICON hIcon = AtlLoadIconImage(IDR_MAINFRAME,
LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON));
SetIcon(hIcon, TRUE);
HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME,
LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));
SetIcon(hIconSmall, FALSE);
//subclassing
an Edit control
m_NumberOnlyEdit.SubclassWindow(GetDlgItem(IDC_EDIT_NUMBER));
m_NumberOnlyEdit.SetWindowText(_T("NumberOnlyEdit
Subclassing"));
int lineCount
= m_NumberOnlyEdit.GetLineCount();
return TRUE;
}
void OnChar(UINT
nChar, UINT nRepCnt, UINT nFlags)
{
//Only
number or backspace is allowed
if (('0'<=nChar
&& nChar<='9') || (nChar==VK_BACK))
{
//Accept
the default process
SetMsgHandled(FALSE); //or
DefWindowProc();
}
else
{
::MessageBeep(MB_ICONERROR); //Warning
}
}
//...
};
其中CContainedWindowT在内部生成了一个新类,并将所有的内部窗口消息都转发给了控件的父窗口(即对话框),因此可以将特殊消息处理代码放在父窗口的消息映射列表中,这样,就没有必要自己单独创建一个新类了。
注意,这种处理方法需要我们制定一个消息映射的分支编号(本例子中为12),这是一个任意选定的编号(父窗口中可能存在多个分支编号,以分别处理各个控件转发过来的消息):
CMainDlg()
: m_NumberOnlyEdit(this,12)
{
//...
}
BEGIN_MSG_MAP_EX(CMainDlg)
//...
ALT_MSG_MAP(12) //Process
message from m_NumberOnlyEdit control
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
三.一些结论
有上可知,窗口子类化可以实现窗口超类化相同的功能,且更加灵活。
如果控件的父窗口为普通窗口或父控件窗口,可以使用窗口超类化;如果父窗口是对话框,需要对对话框模板中已存在的控件行为进行定制,可以使用窗口子类化。
相关文章推荐
- WTL-窗口超类化(superclassing),窗口子类化(subclassing)
- WTL-窗口超类化(superclassing),窗口子类化(subclassing)
- WTL-窗口超类化(superclassing),窗口子类化(subclassing)
- 窗口的子类化与超类化
- 子类化和超类化区别(介绍Windows的窗口、消息、子类化和超类化)(转)
- 眼见为实(2):介绍Windows的窗口、消息、子类化和超类化
- 介绍Windows的窗口、消息、子类化和超类化
- 眼见为实(2):介绍Windows的窗口、消息、子类化和超类化
- Windows的窗口、消息、子类化和超类化
- 介绍Windows的窗口、消息、子类化和超类化
- 窗口的子类化与超类化
- 窗口子类化与超类化 代码演示
- WTL之窗口超类化(父类化)
- 窗口子类化与超类化
- 窗口子类化与超类化
- 窗口的子类化和超类化
- 介绍Windows的窗口、消息、子类化和超类化
- 窗口的子类化与超类化
- 窗口的子类化与超类化
- 窗口的子类化与超类化