SubclassDlgItem函数

SubclassDlgItem函数用来子类化一个控件。Subclass(子类化)是MFC中最常用的窗体技术之一。子类化完成两个工作:一是把窗体类对象attach到一个windows窗体实体中(即把一个窗体的hwnd赋给该类)。另外就是把该类对象的消息加入到消息路由中,使得该类可以捕获消息。

在OnInitDialog中调用SubclassDlgItem将派生类的控件对象与对话框中的基类控件相连接,则这个基类控件对象变成了派生控件对象。

要在程序中创建新设计的控件,显然不能用自动创建的办法,因为对话框模板对新控件的特性一无所知。程序可以用手工方法创建控件,在调用派生类的Create函数时,派生类会调用基类的Create函数创建控件。用Create函数创建控件是一件比较麻烦的工作,程序需要为函数指定一大堆的控件风格以及控件的坐标和ID。特别是控件的坐标,没有经验的程序员很难确切地安排控件的位置和大小,往往需要反复调整。利用MFC的CWnd::SubclassDlgItem提供的动态连接功能,可以避免Create函数的许多麻烦,该函数大大简化了在对话框中创建派生控件的过程。

大家知道,在用手工方法创建控件时,先要构建一个控件对象,然后再用Create函数在屏幕上创建控件窗口,也就是说,控件的创建工作是由控件对象完成的.动态连接的思路则不同,SubclassDlgItem可以把对话框中已有的控件与某个窗口对象动态连接起来,该窗口对象将接管控件的消息处理,从而使控件具有新的特性。SubclassDlgItem函数的声明为:

BOOL SubclassDlgItem( UINT nID, CWnd* pParent );

参数nID是控件的ID,pParent是指向父窗口的指针。若连接成功则函数返回TRUE,否则返回FALSE。

综上所述,要在程序中使用派生控件,应该按下面两步进行:

  1. 在对话框模板中放置好基类控件。
  2. 在对话框类中嵌入派生控件类的对象。

否则函数将会执行失败,一定要注意!

在OnInitDialog中调用SubclassDlgItem将派生类的控件对象与对话框中的基类控件相连接,则这个基类控件变成了派生控件。例如,如果要在对话框中使用新设计的编辑框控件,应先在对话框模板中的合适位置放置一个普通的编辑框,然后,在OnInitDialog函数中按下面的方式调用SubclassDlgItem即可:

BOOL CMyDialog::OnInitDialog()

{

CDialog::OnInitDialog();

m_MyEdit.SubclassDlgItem(IDC_MYEDIT, this);

return TRUE;

}

下面的代码演示通过配置文件创建自定义按钮,使用“SubclassDlgItem”,并解决没有在对话框模板中放置好基类控件的方法:

CxSkinButton *pSkinBnt = NULL;

pSkinBnt = new CxSkinButton; // del at Clear();

//子类化控件

BOOL ret = pSkinBnt->SubclassDlgItem(id,parent);

//如果执行失败,则说明没有在对话框模板中放置好基类控件

if (!ret)

{

//创建按钮

UINT stype = WS_CHILD|WS_VISIBLE;

pSkinBnt->Create(NULL, stype, rect, parent, id);

}

我调用“SubclassDlgItem”函数成功了,为什么按钮却没有显示呢?一共就两个参数,ID,Parent,检查一下参数传递的是否正确吧!

如果使用了重复的ID,就会出现这种情况。

另外,如果做了变量映射,调用此函数就会触发:Asert(m_hwnd== NULL);

问题缘起

通常如果在对话框中将一个控件映射到一个变量,有三种方法:

1. DDX的方法

2. GetDlgItem的方法,例如CEdit pEdt = (CEdit *)GetDlgItem(IDC_EDIT1);

3. SubclassWindow的方法(或者其扩展SubclassDlgItem),例如
CEdit m_editm_edit.SubclassDlgItem(IDC_EDIT1);

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指针。

SubclassDlgItemGetDlgItem二者的区别

如果只是想调用一个控件对应类的方法,差别不大。只是前者会生成一个类对象,而后者得到指向对象的指针。但如果跟消息有关,则前者会相应消息。例如:

比如我自己写了一个类叫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);

通过这种方式,可以动态改变一个控件的消息处理流程,使得CsuperEdit中重载的消息可以被执行。如果不使用子类型化,则无法执行。

SubclassDlgItem函数相关推荐

  1. MFC控件的SubclassDlgItem

    要在程序中创建新设计的控件,显然不能用自动创建的办法,因为对话框模板对新控件的特性一无所知.程序可以用手工方法创建控件,在调用派生类的Create函数时,派生类会调用基类的Create函数创建控件.用 ...

  2. SubclassWindow和SubclassDlgItem

    通常如果在对话框中将一个控件映射到一个变量,有三种方法: DDX的方法 GetDlgItem的方法,例如CEdit pEdt = (CEdit *)GetDlgItem(IDC_EDIT1); Sub ...

  3. CButtonST的用法详解!

    在想使用CButtonST的工程中加入BtnST.h.BtnST.cpp.BCMenu.h.BCMenu.cpp4个文件.2个类. 1. 在按钮上加入Icon,使Icon和文字同时显示 假设按钮ID为 ...

  4. 【转】为控制台窗口建立消息队列

    介绍Windows的窗口.消息.子类化和超类化 这篇文章本来只是想介绍一下子类化和超类化这两个比较"生僻"的名词.为了叙述的完整性而讨论了Windows的窗口和消息,也简要讨论了进 ...

  5. 转走出MFC窗口子类化迷宫

    http://blog.csdn.net/phunxm/article/details/5621120 MFC向导生成的对话框为模态对话框,当我们在资源编辑器中向对话框拖拽一个按钮IDC_BTN时,其 ...

  6. PreSubclassWindow详细分析

    PreSubclassWindow PreSubclassWindow是一个很好的定制控件的位置.如果我们通过重载CWnd::PreCreateWindow定制控件,而用户在对话框中使用控件.由于对话 ...

  7. VC 基础知识(转载)

    1 句柄句柄是用来标志被应用程序建立或使用的对象的唯一整数.Windows要使用各种各样的句柄来标志窗口.菜单.输出设备和文件等.可以把句柄理解为与指针类似.用户必须通过某种方式来创建句柄,并要保证在 ...

  8. 转:CWnd的函数,以后可以在这儿找了!

    CWnd CObject  └CCmdTarget     └CWnd CWnd类提供了微软基础类库中所有窗口类的基本功能. CWnd对象与Windows的窗口不同,但是两者有紧密联系.CWnd对象是 ...

  9. 数据库中自定义排序规则,Mysql中自定义字段排序规则,Oracle中自定义字段排序规则,decode函数的用法,field函数的用法

    数据库中自定义排序 场景:有一张banner表,表中有一个status字段,有0, 1, 2三个状态位,我想要 1,0,2的自定义排序(这里是重点),然后再进行之上对sequence字段进行二次排序( ...

最新文章

  1. 深思:如何堂堂正正的做事
  2. 今目标戴珂:掘金企业协同
  3. iOS10 UI教程视图的边界与视图的框架
  4. Python中文件的介绍以及操作
  5. ustc小道消息20211213
  6. java 元素居中_如何在ColumnLayout中居中元素
  7. RoboWare Studio使用的部分问题
  8. vue多级菜单的实现
  9. maya要学python吗_Maya入门为什么会这么难?
  10. python爬虫-北京租房可视化分析
  11. vue 引入 360度图片旋转插件 SpriteSpin.js
  12. JavaScript词汇表
  13. 优秀的项目经理需要具备哪些品质?
  14. 烦立停:过度营销的孙宇晨输给了一个结石
  15. 三菱FX系列PLC电池电压低导致程序参数丢失,PROG.E报警灯闪烁的解决办法
  16. 断食法法定分啊发顺丰啊
  17. STM32F407ZG单片机晶振由例程默认推荐的8M换为自定义的4-26M时的注意事项
  18. FFMPEG只编译H264编码
  19. lisp获取qleader端点_基于AutoLISP的点坐标标注
  20. 计算机毕业设计之java+javaweb的影院管理系统-电影院管理系统

热门文章

  1. Python实现bp神经网络识别MNIST数据集
  2. java之设计模式工厂三兄弟之简单工厂模式
  3. C++中的未定义的行为
  4. 自己mini版jquery编写
  5. Cityengine, 3ds MAX, FME
  6. Java学习-Overload和Override的区别
  7. php中global和$GLOBALS[]的分析之一
  8. POJ 1991 Turning in Homework ★(区间DP)
  9. Guava学习笔记(1)--安全地使用null(Using and avoiding null)
  10. 【安装配置】Oracle数据库Linux系统下安装(图形界面)