C++ 中超类化和子类化
超类化和子类化没有具体的代码,其实是一种编程技巧,在MFC和WTL中可以有不同的实现方法。
窗口子类化:
原理就是改变一个已创建窗口类的窗口过程函数。通过截获已创建窗口的消息,从而实现监视或修改已创建窗口类的行为属性。可以用来改变或者扩展一个已存在的窗口的行为,而不用重新开发。比如要获得那些预定义控件窗口类(按钮控件、编辑控件、列表控件、下 拉列表控件、静态控件和滚动条控件)的功能而又要修改它们的某些行为。
子类化的优点主要体现在以下两个方面:首先,它不需要创建新的窗口类,不需要了解一个窗口的窗口过程。这在原来的窗口函数是由别人编写,而且创建过程不可见的情况下非常有用;其次,子类化比较容易实现,因为所有要做的工作仅仅就是写一个窗口函数。
主要步骤为
- 截取该消息,阻止其向原窗口函数发送。
- 修改该消息。
- 修改完毕以后再向原窗口函数发送。
// 保存窗口默认的消息响应函数指针
WNDPROC pSubclassOldEditProc;
// 用于替换子类化窗口的消息响应函数
LRESULT CALLBACK JcEditProcSubClass(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CHAR:
{
::MessageBox(hWnd, "WM_CHAR响应", "子类化", MB_OK);
return 0;
}
//使用完后,消息发回原窗体
default: return ::CallWindowProc(pSubclassOldEditProc, hWnd, message, wParam, lParam);
}
} // 对创建好的窗体进行子类化代码
{
// 创建
HWND hEdit = CreateWindowEx(NULL, "EDIT", "SubClass",
WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, 100,120, 128, 16, hWnd, NULL, hInstance, NULL);
//修改窗口属性,改变消息响应函数
pSubclassOldEditProc = (WNDPROC)::SetWindowLong(hEdit, GWL_WNDPROC, (DWORD)JcEditProcSubClass);
// 显示
ShowWindow(hEdit, nCmdShow);
UpdateWindow(hWnd);
}
窗口超类化:
窗口超类化是在窗口类——WNDCLASS或WNDCLASSEX(非MFC类概念)级别进行的改变窗口类特征的。改变已有窗口类的行为属性。
- 通过调用 GetClassInfoEx 来获得想要进行超类化操作的窗口类的信息。函数GetClassInfoEx 需要一个指向 WNDCLASSEX 结构的指针,用于当成功返回时填入窗口类的信息。
- 按需要修改 WNDCLASSEX 结构的成员,其中有两个成员必须修改:
hInstance 存放程序的实例句柄
lpszClassName 指向一个新类名的指针
不必修改成员 lpfnWndProc,但大多数情况下还是需要的。但要记住如果要使用函数 CallWindowProc
调用老窗口的过程,那就必须保存成员 lpfnWndProc 的原值。 - 注册修改完的 WNDCLASSEX
结构,得到一个具有旧窗口类某些特性的新窗口类。 - 用新窗口类创建窗。
WNDPROC pSuperOldEditProc;// 保存窗口默认消息处理函数
// 用于替换的超类化消息响应函数
LRESULT CALLBACK JcEditProcSuper(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CHAR:
{
::MessageBox(hWnd, "WM_CHAR响应", "超类化", MB_OK);
return 0;
}
default: return ::CallWindowProc(pSuperOldEditProc, hWnd, message, wParam, lParam);
}
} // 创建超类化控件代码
{
// 取得原控件信息
WNDCLASSEX myeditClass;
::GetClassInfoEx(hInstance, "EDIT", &myeditClass);
// 保存原控件默认消息处理函数
pSuperOldEditProc = myeditClass.lpfnWndProc;
// 设置替换的消息处理函数
myeditClass.lpfnWndProc = JcEditProcSuper;
// 指定新的窗口类名字
myeditClass.lpszClassName = "JcilyEdit";
// 设置结构体大小
myeditClass.cbSize = sizeof(WNDCLASSEX);
// 注册新信息
RegisterClassEx(&myeditClass);
// 创建
HWND hEdit = CreateWindowEx(NULL, myeditClass.lpszClassName, "SuperClass",
WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, 100,100, 128, 16, hWnd, NULL, hInstance, NULL);
// 显示
ShowWindow(hEdit, nCmdShow);
UpdateWindow(hWnd);
}
窗口子类化和超类化的区别
(1) 子类化修改窗口过程函数, 超类化修改窗口类(新的窗口类名)
(2) 子类化是在窗口实例级别上的,超类化是在窗口类(WNDCLASS)级别上的。
(3) 超类化可以完成比子类化更复杂的功能,在SDK范畴上,可以认为子类化是超类化的子集。
(4) 子类化只能改变窗口创建后的性质,对于窗口创建期间无能为力(无法截获ON_CREATE 事件),而超类化可以实现;超类化不能用于Windows创建的窗口,子类化可以。
(5) 超类化可以修改包含窗体背景等属性,而子类化不能。
C++ 中超类化和子类化的更多相关文章
- C++ 中超类化和子类化常用API
在windows平台上,使用C++实现子类化和超类化常用的API并不多,由于这些API函数的详解和使用方法,网上一大把.本文仅作为笔记,简单的记录一下. 子类化:SetWindowLong,GetWi ...
- 窗口的子类化与超类化——子类化是窗口实例级别的,超类化是在窗口类(WNDCLASS)级别的
1. 子类化 理论:子类化是这样一种技术,它允许一个应用程序截获发往另一个窗口的消息.一个应用程序通过截获属于另一个窗口的消息,从而实现增加.监视或者修改那个窗口的缺省行为.子类化是用来改变或者扩展一 ...
- Win32中安全的子类化(翻译)
关于子类化的话题虽然有些旧,但它至今仍然不失为一种开发Windows的强有力技术,在MFC的内核.甚至.NET的内核中都离不开它,希望本连载能对Windows开发的爱好者有所帮助. 原文标题:Safe ...
- 眼见为实(2):介绍Windows的窗口、消息、子类化和超类化
眼见为实(2):介绍Windows的窗口.消息.子类化和超类化 这篇文章本来只是想介绍一下子类化和超类化这两个比较“生僻”的名词.为了叙述的完整性而讨论了Windows的窗口和消息,也简要讨论了进程和 ...
- 窗口 超类化 子类化 HOOK
body { font-family: Bitstream Vera Sans Mono; font-size: 11pt; line-height: 1.5; } html, body { colo ...
- 流畅python学习笔记:第十二章:子类化内置类型
子类化内置类型 在python2.2之后,内置类型都可以子类化,但是有一个注意事项:内置类型不会调用用户定义的类覆盖的特殊方法.这个说起来比较绕口,什么意思呢.我们来看下下面的代码: class Do ...
- 深入理解MFC子类化
子类化,通俗来讲就是用自己的窗口处理函数来处理特定消息,并将自己其他消息还给标准(默认)窗口处理函数.在SDK中,通过SetWindowLong来指定一个自定义窗口处理函数:SetWindowLong ...
- 走出MFC子类化的迷宫
走出MFC子类化的迷宫 KEY WORDS:子类化 SUBCLASSWINDOW MFC消息机制 许多Windows程序员都是跳过SDK直接进行RAD开发工具[或VC,我想VC应不属于RAD]的学习 ...
- 动态子类化CComboBox以得到子控件EDIT及LISTBOX
动态子类化CComboBox以得到子控件EDIT及LISTBOX Joise.LI写于2004-4-6 ComboBox是比较常用的一个控件,有三种样式:CBS_SIMPLE(简单),CBS_DROP ...
随机推荐
- Sqlserver2008 表分区教程
先声明..Sql2008只有企业版才能够搞这个表分区.其他版本请自觉更改.. 哥在这里费了很长时间劲..结果还是老老实实的重装.. 表分区定义 一般情况下,我们建立数据库表时,表数据都存放在一个文件里 ...
- editplus如何配置php编译环境?
为什么要配置php编译? 因为,要先看看 php文件是否能够 编译得过去, 有没有错误, 如果有错误, 不能通过编译, 则肯定不能运行. 所以, 可以先看一下编译 得不得行. 在preferences ...
- jQuery.Callbacks 源码解读二
一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...
- Java五道输出易错题解析(避免小错误)
收集了几个易错的或好玩的Java输出题,分享给大家,以后在编程学习中稍微注意下就OK了. 1. 看不见的空格? 下面的输出会正常吗? package basic; public class Integ ...
- 编译CDH Spark源代码
如何编译CDH Spark源代码 经过漫长的编译过程(我编译了2个半小时),最终成功了,在assembly/target/scala-2.10目录下面有spark-assembly-1.0.0-cdh ...
- lua操作json,mysql,redis等
==========================example for lua json======================= local cjson = require("cj ...
- java中堆栈(stack)和堆(heap)(还在问静态变量放哪里,局部变量放哪里,静态区在哪里.....进来)
(1)内存分配的策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编 译时就可以给 ...
- jetbrick,新一代 Java 模板引擎,具有高性能和高扩展性
新一代 Java 模板引擎,具有高性能和高扩展性. <!-- Jetbrick Template Engineer --> <dependency> <groupId&g ...
- 如何使用java自定义注解?demo
1.Description.java package kzfy.bk.com; import java.lang.annotation.Documented; import java.lang.ann ...
- 一起入门python7之函数参数
上一节课简单的讲了一下函数.那么今天来给大家讲一下函数参数.用案例说话哈.上一节课只是让大家有比较简单的了解,那么这节我们来细化一下哈.>>>def hello(x): ...