解说Win32的窗口子类化

2016-01-29 11:59 8 1 收藏

解说Win32的窗口子类化,解说Win32的窗口子类化

【 tulaoshi.com - win32 】

解说Win32的窗口子类化
     
     作者:李马(home.nuc.edu.cn/~titilima)

下载本文的配套源代码
       
也许你需要一个特殊的Edit来限制浮点数的输入,但是现有的Edit却并不能完成这项工作——因为它只能够单纯的限制大小写或者纯数字。当你在论坛上求救的时候,某个网友告诉你:“用子类化。”你也许会在看到一线曙光的同时多出了一连串的问题:何为子类化?子类化的原理是什么?如何实现子类化?下面就让我从一个简单的C++程序开始,一步步解开你的疑团吧。
 首先,我为你列出以下这个C++程序:

#includeusing namespace std;class Parent{public:  void func(void) { cout << "func of Parent" << endl; }};class Child : public Parent{public:  void func(void) { cout << "func of Child" << endl; }};void main(){  Parent p;  Child c;  p.func();  c.func();}

现在我来解说一下。这段代码中我定义了两个C++类:父类和子类,并且子类是继承自父类的;它们有一个具有相同名称的成员函数func。在main函数中,我分别构造了父类和子类的对象,并调用了它们各自的成员函数func。结果如下:

func of Parentfunc of Child

简单说来,这段代码就是子类根据自己的需要改写了func成员函数。而Win32的子类化的原理也与此类似,只不过子类化实际上并没有像C++一样重载哪个函数,而是靠拦截Windows系统中的某些消息来自己进行处理罢了。举例来说,请大家看以下这段简单的窗口回调过程:

LRESULT CALLBACK ProcMain(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam){  switch (Msg)  {  case WM_CLOSE:    EndDialog(hDlg, 0);    break;  case WM_DESTROY:    PostQuitMessage(0);    break;  }  return 0;}

在这个回调之中,我手动处理了两个消息:在单击了“关闭”按钮(WM_CLOSE)的时候,我将对话框关闭(EndDialog);在对话框销毁(WM_DESTROY)的时候,我向系统消息队列中发送了退出的消息来完成结束工作(PostQuitMessage)。也就是说,如果把WM_CLOSE的响应代码改成:

case WM_CLOSE:    ShowWindow(hDlg, SW_MINIMIZE);    break;

这样一来,这个对话框就会和MSN一样,在单击了“关闭”之后,就会完成最小化的工作了。那么,对于窗口过程已定义好的系统控件,将如何手动响应它的消息呢?
   我们可以用函数指针的办法,将我们感兴趣的消息拦截下来,处理完之后再让预定义的窗口过程处理。这个过程大致如下:

WNDPROC OldProc;  OldProc = (WNDPROC)SetWindowsLong(hWnd, GWL_WNDPROC, (LONG)NewProc);

当然,这里的新窗口过程NewProc是预先由你实现好的。上述代码执行以后,系统在处理hWnd的窗口消息时,就会先进入你实现的NewProc回调过程,然后在处理过你感兴趣的消息之后,通过CallWindowProc函数和你预先保存的OldProc再次回到原来的回调过程中完成剩余的工作。
   以上就是窗口子类化的原理分析,下面我通过一个实例来实际解说如何对窗口进行子类化。

这个例子的界面如下:



界面上方的编辑框是用来限制浮点输入的,下面则是一个普通的超级链接。
   好了,下面我开始按步骤完成对这两个窗口的子类化:
   第一步,在主窗口对话框初始化的时候,保存原有的窗口过程,并设置新的窗口过程。代码如下:

case WM_INITDIALOG:    EditProc = (WNDPROC)SetWindowLong(GetDlgItem(hDlg, IDC_EDIT), GWL_WNDPROC, (LONG)ProcFloat);    StaticProc = (WNDPROC)SetWindowLong(GetDlgItem(hDlg, IDC_ST_HOMEPAGE), GWL_WNDPROC, (LONG)ProcLink);    break;

第二步,实现浮点编辑框的窗口过程:

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com)
LRESULT CALLBACK ProcFloat(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam){  if (Msg == WM_CHAR && wParam != ''.'' && (wParam = ''9'') && wParam != VK_BACK)  {    MessageBeep(MB_OK);    return 0;  }  else    return CallWindowProc(EditProc, hWnd, Msg, wParam, lParam);}

这里需要解释的是,由于控件本身的需求,所以只需要拦截一个消息,就是接收字符的WM_CHAR。当用户输入的字符不是小数点、0~9以及退格键(注意不要少了退格键,否则你将会发现你的编辑框无法删除输入错误的数字)的时候,就发出一声声音以提示输入错误。至于其它的消息,则调用原有的回调函数进行处理。
   第三步,实现超级链接的窗口过程:

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com)
LRESULT CALLBACK ProcLink(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam){  switch (Msg)  {  case WM_SETCURSOR:    SetCursor(LoadCursor(NULL, IDC_HAND));    break;  case WM_LBUT

来源:https://www.tulaoshi.com/n/20160129/1484140.html

延伸阅读
环境变量设置:单击桌面我的电脑右键属性-高级-环境变量-双击Path项,添加C:MySQL5.1.40bin目录,如果要使用SDK开发,则要添加Lib和include目录到对应的Lib和include环境变量中; 环境变量设好,在开始菜单-运行-CMD,执行MySQLD,或是直接切换到C:MySQL5.1.40bin目录双击运行MySQLD.exe服务程序,也可以服务的形式运行: 注意mysql安装目录不要...
CNTService 类 当我创建 C++ 对象封装 Windows 函数时,我尝试为我封装的每个 Windows API 除了创建成员函数外,还做一些别的工作,我尝试让对象更容易使用,降低实现特定项目所需的代码行数。因此我的对象是基于我想让这个对象做什么?而不是Windows 用这些 APIs 做什么? CNTService 类包含一些用来解析命令行的成员函数,为了处理服...
众 所 周 知, 在Windows95/98 的Win32 on Intel x86 体 系 中 利 用 了 处 理 器 的 三 环 保 护 模 型 中 的 零 环(Ring0, 最 高 权 限 级 别) 和 三 环(Ring3, 最 低 权 限 级 别)。 一 般 应 用 程 序 都 运 行 在Ring3 下, 受 到 严 格 的" 保 护", 只 能 规 矩 地 使 用Win32API。 如 果 我 们 想 进 行 一 些 系 ...
标签: 电脑入门
有用户在双击安装某个软件时,经常会弹出XXX.EXE不是有效Win32应用程序的错误提示。 当然,有时即使我们双击运行任意一个EXE格式的可执行文件,同样会出现这样的错误提示。那么如何才能够避免系统出现不是有效Win32应用程序问题呢。 如果仅仅是在安装某些软件时,才弹出错误信息,这说明我们安装的程序包不完整或者是程序安装不成功,此时可...
http://blog.vckbase.com/Files/BastEt/testnodll.zip VC2003编译,我想用VC6肯定也能编译通过,不过机器上没装,哪个有空帮我看看在VC6下能达到多少字节? 原始文章来自:http://blog.csdn.net/sunwang123456/archive/2005/10/18/508706.aspx #define WIN32_LEAN_AND_MEAN #define WINVER 0x0500 #include windows.h //===================...

经验教程

772

收藏

35
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部