DDX_Control、SubclassWindow和SubclassDlgItem
文章参考地址:http://blog.sina.com.cn/s/blog_86fe5b440101au88.html;http://www.cnblogs.com/riskyer/p/3424278.html
问题缘起
通常如果在对话框中将一个控件映射到一个变量,有三种方法:
1. DDX的方法
2. GetDlgItem的方法,例如CEdit pEdt = (CEdit *)GetDlgItem(IDC_EDIT1);
3. SubclassWindow的方法(或者其扩展SubclassDlgItem),例如CEdit m_edit;m_edit.SubclassDlgItem(IDC_EDIT1);
SubclassWindow
CWnd::SubclassWindow(HWND hWnd)中调用两个主要操作:Attach(hWnd)和WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)AfxGetAfxWndProc());
前者的作用是把CWnd中的m_hWnd设置为hWnd,后者的作用是改变该窗口的窗口函数为AfxGetAfxWndProc()的返回.
AfxGetAfxWndProc返回了AfxWndProc的函数指针,即窗口函数的指针,AfxWndProc包裹了AfxCallWndProc,后者又调用了pWnd->WindowProc(nMsg, wParam, lParam);。
可见SubclassWindow完成了两项功能:
1. 我们对该窗体实例调用成员函数将会直接改变相关窗体句柄对应的窗体(Attach)
2. 系统传给相关窗体句柄的消息会先经过该窗体实例的消息映射(SetWindowLong)。
SubclassDlgItem
调用了SubclassWindow,但之前调用了::GetDlgItem获取一个控件ID对应的窗口句柄。
GetDlgItem
只是调用::GetDlgItem获得控件ID对应的窗口句柄,然后使用FromHandle将句柄转换为CWnd指针。
SubclassDlgItem和GetDlgItem二者的区别
如果只是想调用一个控件对应类的方法,差别不大。只是前者会生成一个类对象,而后者得到指向对象的指针。
但如果跟消息有关,则前者会相应消息。例如:
比如我自己写了一个类叫CSuperEdit(父类为CEdit),在该类中我声明了void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);并在消息循环里添加了ON_WM_CHAR 一行。现在我只要在对话框CProg1Dlg 中声明CSuperEdit m_edit;然后在CProg1Dlg::OnInitDialog中,添加以下代码,就完成了“超类化”:
{
HWND hWndControl = ::GetDlgItem(pParent->m_hWnd, IDC_EDIT1);
m_edit.SubclassWindow (hWndControl);
}或者
BOOL CProg1Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_edit.SubclassDlgItem(IDC_EDIT1, this);
return TRUE;
}通过这种方式,可以动态改变一个控件的消息处理流程,使得CsuperEdit中重载的消息可以被执行。如果不使用子类型化,则无法执行。
在自绘窗口的时候,子类化是MFC最常用的窗体技术之一。什么是子类化?窗口子类化就是创建一个新的窗口函数代替原来的窗口函数。
Subclass(子类化)是MFC中最常用的窗体技术之一。子类化完成两个工作:一是把窗体类对象attach到一个windows窗体实体中(即把一个窗体的hwnd赋给该类)。另外就是把该类对象的消息加入到消息路由中,使得该类可以捕获消息。
而通常我们会碰到DDX_Control、SubclassWindow、SubclassDlgItem等,不同的子类化方法。首先先看下面的代码:
void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
{
if ((rControl.m_hWnd == NULL) && (rControl.GetControlUnknown() == NULL)) // not subclassed yet
{
ASSERT(!pDX->m_bSaveAndValidate); pDX->PrepareCtrl(nIDC);
HWND hWndCtrl;
pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
if ((hWndCtrl != NULL) && !rControl.SubclassWindow(hWndCtrl))
{
ASSERT(FALSE); // possibly trying to subclass twice?
AfxThrowNotSupportedException();
}
#ifndef _AFX_NO_OCC_SUPPORT
else
{
if (hWndCtrl == NULL)
{
if (pDX->m_pDlgWnd->GetOleControlSite(nIDC) != NULL)
{
rControl.AttachControlSite(pDX->m_pDlgWnd, nIDC);
}
}
else
{
// If the control has reparented itself (e.g., invisible control),
// make sure that the CWnd gets properly wired to its control site.
if (pDX->m_pDlgWnd->m_hWnd != ::GetParent(rControl.m_hWnd))
rControl.AttachControlSite(pDX->m_pDlgWnd);
}
}
#endif //!_AFX_NO_OCC_SUPPORT }
}
我们发现 DDX_Control()函数中调用了SubclassWindow(),再看SubclassWindow()里写了什么:
// From VS Install PathVC98MFCSRCWINCORE.CPP
BOOL CWnd::SubclassWindow(HWND hWnd)
{
if (!Attach(hWnd))
return FALSE; // allow any other subclassing to occur
PreSubclassWindow(); // now hook into the AFX WndProc
WNDPROC* lplpfn = GetSuperWndProcAddr();
WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,
(DWORD)AfxGetAfxWndProc());
ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc()); if (*lplpfn == NULL)
*lplpfn = oldWndProc; // the first control of that type created
#ifdef _DEBUG
else if (*lplpfn != oldWndProc)
{ ::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);
}
#endif return TRUE;
}
很显然,SubclassWindow()中调用了Attach()函数和PreSubclassWindow()函数,由于SubclassWindow()函数是不可重载的,而PreSubclassWindow()函数是可重载的,所以我们经常重载PreSubclassWindow()函数,以致于 窗口被子类化之前进行其它的必要的子类化,看下它原来的声明:
CWnd::PreSubclassWindow
virtual void PreSubclassWindow( );
而SubclassWindow又与SubclassDlgItem有什么区别?前者用于一切具有HWND的窗体,后者只限定于对话框控件
用法:在OnInitDialog中调用SubclassDlgItem将派生类的控件对象与对话框中的基类控件相连接,则这个基类控件对象变成了派生控件对象
DDX_Control、SubclassWindow和SubclassDlgItem的更多相关文章
- 【C++】DDX_Control、SubclassWindow和SubclassDlgItem的区别
在自绘窗口的时候,子类化是MFC最常用的窗体技术之一.什么是子类化?窗口子类化就是创建一个新的窗口函数代替原来的窗口函数. Subclass(子类化)是MFC中最常用的窗体技术之一.子类化完成两个工作 ...
- 关于SubclassWindow()和SubclassDlgItem
msdn上的解析 CWnd::SubclassWindowBOOL SubclassWindow( HWND hWnd ); Return Value Nonzero if the function ...
- mfc subclasswindow attach setwindowlong使用区别
1. CWnd::Attach BOOL Attach( HWND hWndNew ); 返回值:如果成功,则返回非零值:否则返回0. 参数: hWndNew 指定了Windows窗口的句柄. 说明: ...
- MFC分类
屏幕截图(带光标) MFC Button控件自绘 WM_CTLCOLOR消息 MFC窗口创建.销毁消息流程 DDX_Control.SubclassWindow和SubclassDlgItem 隐藏系 ...
- 深入理解MFC子类化
子类化,通俗来讲就是用自己的窗口处理函数来处理特定消息,并将自己其他消息还给标准(默认)窗口处理函数.在SDK中,通过SetWindowLong来指定一个自定义窗口处理函数:SetWindowLong ...
- MFC控件的SubclassDlgItem
MFC控件的SubclassDlgItem 要在程序中创建新设计的控件,显然不能用自动创建的办法,因为对话框模板对新控件的特性一无所知.程序可以用手工方法创建控件,在调用派生类的Create函数时,派 ...
- MFC知识点(DDX_Control 与 DDX_Text ,ON_COMMAND和ON_MESSAGE)
1.DDX_Control 与 DDX_Text 区别 DDX_TEXT()的作用可以理解为把字符串变量和控件的文本(WindowText)关联起来, DDX_Control()的作用可以理解为把变量 ...
- error LNK2005: DDX_Control 已经在 uafxcwd.lib(wincore2.obj) 中定义
编译错误提示: 1>afxnmcdd.lib(wincore2.obj) : error LNK2005: "void __stdcall DDX_Control(classCData ...
- WTL error C3861: 'DDX_Control': identifier not found
error C3861: 'DDX_Control': identifier not found 继承类加上 public CWinDataExchange<CMainDlg>, ...
随机推荐
- git merge最简洁
一.开发分支(dev)上的代码达到上线的标准后,要合并到 master 分支 git checkout devgit pullgit checkout mastergit merge devgit p ...
- lnmp配置支持thinkphp和nginx路由url重写
ThinkPHP3.2.3项目放到lnmp环境之后只能打开首页,或者通过传参方式打开控制器,否则就一直显示404页面.搞了一上午,终于解决了 step1: 修改php.ini cgi.fix_path ...
- MySQL的边角料
//1查询对应数据库所有的表 SELECT * FROM information_schema.`TABLES` WHERE TABLE_SCHEMA ="数据库名" 2 查询数据 ...
- python-集合类型
集合具有唯一性(集合中的元素各不相同),无序性,确定性(集合中的元素是不可改变的,不能是列表,字典以及集合本身) 1.add(self, *args, **kwargs),union(self, *a ...
- ssh安装和使用
1.基础知识 ssh用于远程登陆,linux默认安装了client,如果需要被登陆则需要安装 server 2.安装 apt-get install openssh-server 检查是否安装成功 a ...
- POJ1236_A - Network of Schools _强连通分量::Tarjan算法
Time Limit: 1000MS Memory Limit: 10000K Description A number of schools are connected to a compute ...
- c++ constructor, copy constructor, operator =
// list::push_back #include <iostream> #include <list> class element{ private: int numbe ...
- Eclipse中JS文件红叉处理
使用新版本的Eclipse 或者 MyEclipse,项目中的 JS文件出现红叉,让人觉得项目中存在错误代码,给人的感觉很不爽. 记录一下去掉红叉的方法: 第1步: 打开工作空间中的项目找到项目的 . ...
- 「日常训练」Soldier and Badges (CFR304D2B)
题意 (Codeforces 546B) 问对一个序列最少需要增减几个1能使其彼此不同. 分析 模拟处理.需要注意的是,尽管题目中说了an<=3000,问题是,如果一群a全是3000呢(滑稽), ...
- 常用模块(chardet)
作用:检测二进制的编码格式,不是百分百正确 import chardet f = open('test.txt', 'rb')data = f.read()print(data)result = ch ...