解说Win32的窗口子类化

原创 2004年03月30日 19:26:00

  也许你需要一个特殊的Edit来限制浮点数的输入,但是现有的Edit却并不能完成这项工作——因为它只能够单纯的限制大小写或者纯数字。当你在论坛上求救的时候,某个网友告诉你:“用子类化。”你也许会在看到一线曙光的同时多出了一连串的问题:何为子类化?子类化的原理是什么?如何实现子类化?下面就让我从一个简单的C++程序开始,一步步解开你的疑团吧。
  首先,我为你列出以下这个C++程序:
#include <iostream>
using 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 Parent
func 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;
  第二步,实现浮点编辑框的窗口过程:
LRESULT CALLBACK ProcFloat(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  if (Msg == WM_CHAR && wParam != '.' && (wParam <= '0' || wParam >= '9') && wParam != VK_BACK)
  {
    MessageBeep(MB_OK);
    return 0;
  }
  else
    return CallWindowProc(EditProc, hWnd, Msg, wParam, lParam);
}
  这里需要解释的是,由于控件本身的需求,所以只需要拦截一个消息,就是接收字符的WM_CHAR。当用户输入的字符不是小数点、0~9以及退格键(注意不要少了退格键,否则你将会发现你的编辑框无法删除输入错误的数字)的时候,就发出一声声音以提示输入错误。至于其它的消息,则调用原有的回调函数进行处理。
  第三步,实现超级链接的窗口过程:
LRESULT CALLBACK ProcLink(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  switch (Msg)
  {
  case WM_SETCURSOR:
    SetCursor(LoadCursor(NULL, IDC_HAND));
    break;
  case WM_LBUTTONDOWN:
    ShellExecute(NULL, "open", "
http://home.ncust.edu.cn/~titilima", NULL, NULL, SW_SHOWNORMAL);
    break;
  default:
    return CallWindowProc(StaticProc, hWnd, Msg, wParam, lParam);
  }
  return 0;
}
  这段代码很容易明白:它完成了两件事,其一是设置光标指针为手形(注意:对于较早的Windows系统,是没有预定义的IDC_HAND指针的,这个时候你需要在EXE的资源中自己画一个手形指针,比如Delphi之中的手形指针就是自己画的),其二是当单击了鼠标左键的时候打开你想打开的网页链接。
  其实对于超级链接,它更主要的东西是在子类化之外实现的——就是它的字体颜色(注意这段代码是在主窗口对话框的回调过程中实现的):
  case WM_CTLCOLORSTATIC:
    if (GetDlgItem(hDlg, IDC_ST_HOMEPAGE) == (HWND)lParam)
    {
      SetTextColor((HDC)wParam, 0xff0000);
      SetBkMode((HDC)wParam, TRANSPARENT);
      return (LRESULT)CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
    }
    break;
  还有几点要说明的是:1、你的这个Static超链接必须拥有一个唯一的资源ID,比如我的这个就是IDC_ST_HOMEPAGE,这样才能用GetDlgItem获得它的句柄来完成子类化;2、你必须为它设置SS_NOTIFY样式,以保证在单击它的时候它能够通知父窗口对话框;3、单击它打开网页的处理也可以放在子类化之外,处理主窗口对话框的WM_COMMAND消息也可以实现这一功能。

  关于Win32的窗口子类化就介绍到这里了,你可以点这里下载本文的配套源代码,代码中有详细的注释。

窗口子类化实现自绘按钮如此简单

有没有发现利用createwindow创建按钮感觉太单调,msdn上说的owndraw 按钮太复杂,其实子类化按钮,可以很方便的实现自绘按钮,只需要会点贴图知识就行了。 下面采用gdi+贴图:(关于...
  • dai_jing
  • dai_jing
  • 2013年04月21日 23:06
  • 2988

WIN32窗口子类化----自定义Edit控件的右键菜单

前言 Win32应用程序中,子控件的消息都是分发到其父窗口的消息处理函数中去了,这对于我们需要自定义子控件的某些特性时时十分不方便的,还好,Windows为我们提供了控件子类化的相关接口A...
  • mfcing
  • mfcing
  • 2015年03月28日 21:35
  • 3512

深入Windows窗体原理及控件重绘技巧

之前有学MFC的同学告诉我觉得Windows的控件重绘难以理解,就算重绘成功了还是有些地方不明白,我觉得可能很多人都有这样的问题,在这里我从Windows窗体的最基本原理来讲解控件的WM_DRAWIT...
  • wenzhou1219
  • wenzhou1219
  • 2013年12月29日 13:46
  • 20520

4种控件自绘技术类型分析

本文全面详细分析了四种控件自绘技术,包含控件颜色修改技术WM_CTLCOLOR、用户自绘CustomDraw技术、拥有者自绘OwnerDraw技术WM_DRAWITEM和控件子类化技术,并分别列出了各...
  • xiao3404
  • xiao3404
  • 2016年12月17日 14:14
  • 525

WIN32窗口子类化

理论:如果你曾经在 Windows 环境下编过程序,有时候就会发现:有一个现成的窗口,几乎有你所需要的全部功能,但还不完全一样(否则就没有必要讲这一节了)。你曾遇到过这样的处境吗,如果你需要一个具有过...
  • hnhyhongmingjiang
  • hnhyhongmingjiang
  • 2008年03月06日 15:54
  • 1859

Win32的窗口子类化

也许你需要一个特殊的Edit来限制浮点数的输入,但是现有的Edit却并不能完成这项工作――因为它只能够单纯的限制大小写或者纯数字。当你在论坛上求救的时候,某个网友告诉你:“用子类化。”你也许会在看到一...
  • chaos_epimetheus
  • chaos_epimetheus
  • 2012年09月05日 14:32
  • 663

Windows下子类化目标窗口的方法

当需要干预目标程序的某些操作的时候,除了以前提到的Hook,还可以使用“子类化”目标窗口的方法。先假设一种场合:当需干预目标程序的窗口的某个Panel上的点击事件(类似的也可以)的时候,如果使用HOO...
  • sunshinwong
  • sunshinwong
  • 2015年01月23日 16:15
  • 761

[学习笔记]窗口子类化实例

窗口子类化实例:点击一个按钮,在按钮本身的消息(按钮的消息回调函数)中弹出对话框,而不是在COMMAND(父类的消息回调函数)消息中弹出对话框。...
  • cyxvc
  • cyxvc
  • 2015年10月02日 18:43
  • 458

DirectUI笔记(一)窗口子类化

在看DirectUI的代码,尝试着写一些理解,可能有误,同时也不知道能写多少。写到哪算哪吧。 先谈谈窗口的子类化。 什么是DirectUI呢? DirectUI界面库取名自微软的...
  • Marcelxx
  • Marcelxx
  • 2013年07月11日 11:04
  • 785

解说win32的窗口子类化

解说Win32的窗口子类化 分享到:新浪微博腾讯微博更多0 收藏 发布日期: 2004-12-21 14:07 浏览次数: 3846次 标  签: windows 文章评分: ...
  • bsnry
  • bsnry
  • 2013年08月06日 14:24
  • 1082
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:解说Win32的窗口子类化
举报原因:
原因补充:

(最多只允许输入30个字)