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 ...
随机推荐
- 图书管理系统——APP平台开发
http://www.w3school.com.cn/php/ 初步计划采用PHP 开发网站. 一定要独立建立一套图书管理系统, 尤其唯一性质的概念,整合,甚至中英文图书概念的而整合.一本书一个页. ...
- android-解决EditText的inputType为Password时, 字体不一致的问题
今天做项目的时候,发现当edittext 的InputType为password时,它的字体和原来不一样: 网上找了一下,给出了解决办法: 第一: 去掉xml文件中的password配置,在代码中编写 ...
- 工作中linux定时任务的设置及相关配置
工作中会用到定时任务,来处理以前采集来的数据备份, 每周一凌晨4点执行一次 0 4 * * */1 find/data/templatecdr/oracle/dcndatabak/ -type ...
- 使用cachemanager做缓存(Session的缓存)
1.我在这里直接用 cachemanager.redis 往redis里面存储缓存数据2.步骤 1)下载CacheManager.Redis(包含了CacheManager.Core) 下载Stack ...
- JMS的可靠性
---------------------------------------------------------------------------------------------------- ...
- C语言动态内存分配
考虑下面三段代码: 片段1 void GetMemory(char *p) { p = (); } void Test(void) { char *str = NULL; GetMemory(str) ...
- jdk的安装及配置
前几天重新了下系统,所以JDK也要重新安装,顺带温故了安装及配置的过程,记录下来.(安装的版本是JDK1.7.0) 后面基本都是点下一步(i第一步选:开发工具),路径我改为E:/java/jdk 1. ...
- [译]git rebase
rebase就是重新定义你分支的起点, 分支上的commit将生成对应的新的commit并放在你指定的新的起点commit后, 分支上的老commit将被删除. rebase就是将你的分支从一个com ...
- Sturts2的action不执行任何方法的原因
今天用<s:url action="xxx">调用action的时候出现了一个“异常”, action里的任何方法都没有执行,直接返回success,而且没有任何报错. ...
- getField方法
getField方法是ThinkPHP中用来获取字段值的方法,区别于select和find方法,通常仅用于获取个别字段的值.但是事实上并没有那么简单,该方法的用法总结如下: 获取某个字段值这个是get ...