如何子类化(SubclassWindow)窗体

2024-02-05 16:58

本文主要是介绍如何子类化(SubclassWindow)窗体,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://blog.csdn.net/yuntongsf/article/details/4443356

窗口子类化的作用

窗口子类化技术最大的特点就是能够截取 Windows 的消息。一旦用户自定义的窗口函数截取了传向原窗口函数的消息,就可以对被截取的消息进行如下处理:

将其传给原来的窗口函数。这是对大多数消息应该采取的措施,因为子类通常只对原来的窗口特性作少量的改动

截取该消息,阻止其向原窗口函数发送。

修改该消息,修改完毕以后再向原窗口函数发送。

Windows SDK 提供了一些设计好的窗口类,如 EDIT 、 LISTBOX 、 TREEVIEW 等。通过截取这些通用窗口类的消息,用户程序可以为它们添加新的特性,改善其外观,扩充其功能。

子类化的优点主要体现在以下两个方面:首先,它不需要创建新的窗口类,不需要了解一个窗口的窗口过程。这在原来的窗口函数是由别人编写,而且创建过程不可见的情况下非常有用;其次,子类化比较容易实现,因为所有要做的工作仅仅就是写一个窗口函数

 

 VC 中实现窗口子类化

上面介绍的子类化是从 Windows 本身的窗口函数概念来讲的,实际上属于 SDK ( Software Development Kit )编程的范畴,在 MFC 中情况有所不同。下面将分别描述在这两种情况下窗口子类化实现的方法。

 

VC 中基于 SDK 编程的窗口子类化

VC 中基于 SDK 编程的窗口子类化的基本步骤如下:

(1)        正常创建原始窗口,得到窗口的句柄。

(2)        调用 GetWindowLong 得到原来的窗口函数 OldWndProc 。

(3)        调用 SetWindowLong 设置新的窗口函数 NewWndProc 。

新的窗口函数的代码如下所示:

LRESULT NewWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{

       if(message==WM_IcareIt)

       {

              // 截取自己感兴趣的消息,作一些处理,达到改变特性的目的

   }

       // 必要时可以调用原来的窗口函数,使被子类化的窗口仍具有原来的很多特性

   return CallWndowProc(OldWndProc,hWnd,message,wParam,lParam);

}

值得注意的是,在调用旧的窗口函数时,不能直接用 OldWndProc(…) ,而必须用函数 CallWndProc 进行调用,否则会出现堆栈错误。

MFC 编程中的窗口子类化

MFC 窗口实际上已经是被子类化的窗口。所有的 MFC 窗口共享同一个 窗口函数,由这个窗口函数根据窗口句柄,查找这个窗口对应的 CWnd 派生类实例,再通过消息映射这个窗口类的消息处理函数。鉴于以上原因,在 MFC 中要子类化一个窗口就比较容易了,因为你的任务只是编写一个新的 MFC 窗口类而不需要写一个窗口函数。

假如我们现在有一个对话框,里面有一个编辑控件,我们只希望在该控件中接受非数字字符输入,我们可以拦截WM_CHAR 消息,在它的处理函数中忽略任何数字的输入。 MFC 编程中窗口子类化的具体实现步骤在下一节笔者将用一个简单的实例来加以说明。

 

VC 中窗口子类化的应用举例

MFC 为广大编程者提供了很多功能丰富的窗口类,如果能在这些通用窗口类的基础上进行子类化的话,将会给编程者带来很多便利。下面举一个例子来说明 MFC 编程中的子类化是多么的简单易行。该例完成上面提到的在编辑控件只接受非数字字符输入的功能。实现这个子类化的基本步骤和相关代码如下:

( 1 )利用 AppWziard 创建一个基于对话框的程序 SubClassing 。

( 2 )对 MFC 提供的标准的对话框中的控件进行修改,删除 MFC 提供的静态文本控件,添加自己的一个编辑控件,设置新控件的 ID 为 IDC_EDIT 。合理布置对话框上各控件的位置,使程序界面布局合理、美观。

( 3 )用 ClassWizard 从 CEdit 类派生一个新的窗口类,新窗口的窗口类叫 CNoNumEdit 。截取 CNoNumEdit 类的WM_CHAR 消息,在 OnChar 函中完成忽略任何数字的输入的处理。实现代码如下:

void CNoNumEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

          TCHAR ch=nChar;

         if(ch>=_T('0')&&ch<=_T('9'))

        {

              AfxMessageBox((" 请不要输入数字! "),MB_OK);

              // 当输入数字字符时将被忽略,并显示警告信息

              return;

        }

        CEdit::OnChar(nChar, nRepCnt, nFlags);// 输入为非数字字符时调用原处理函数

}

( 4 )在对话框窗口类 CSubClassingDlg 的定义中添加变量 CNoNumEdit ed 。在 CSubClassingDlg::OnInitDialog() 函数中调用 CWnd 类的成员函数 SubClassWindow 进行子类化。

ed.SubclassWindow(GetDlgItem(IDC_EDIT)->m_hWnd);

( 5 )   在对话框窗口类 CsubClassing 的 OnDestroy 中调用 ed.UnSubClassWindow() 执行窗口类的反子类化。

现在可以编译执行这个程序了,当用户输入数字字符时将会忽略该输入,并显示警告信息。

 

在 Windows 编 程中,适当使用窗口子类化技术,可以很方便地达到改变一个窗口的特性的目的。当然子类化也存在其局限性。实际上,子类化的概念是针对一个已经创建的窗口来 谈的,所以修改窗口函数是在窗口创建之后进行的,在窗口创建期间的消息无法捕获,也就无法处理。另外有些窗口的特性与窗口类本身的属性有关。比如如果一个 窗口类没有 CS_DBLCLKS 属性的话,那么要想通过子类化这些窗口达到处理 WM_LBUTTONDBLCLK 消息的目的是无法实现的。对于子类化的以上局限性,可以通过超类化( SuperClassing )技术消除。   

这篇关于如何子类化(SubclassWindow)窗体的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/681577

相关文章

C# 通过拖控件移动窗体

目录 引言一、通过控件事件移动窗体1、创建窗体界面2、添加控件事件3、添加代码 二、通过windowsAPI移动窗体1、 构建窗体和添加事件2、代码展示 引言 在C#Form窗体设计中,如果我们不需要使用默认边框设计自己个性化的窗体(FromBorderStyle=none时),这时候你会发现拖动窗体的功能就没有了,这里需要自己构建方法让用户可以拖动整个窗体,这里我们使用前辈的

Winform中在窗体中的Paint事件中重绘会导致递归问题?

在 WinForms 应用程序中,如果在窗体的 Paint 事件处理程序中不断调用 Invalidate 方法,确实可能会导致递归调用的问题。这是因为每次调用 Invalidate 方法时,都会向消息队列添加一个绘制消息,当消息队列中的绘制消息被处理时,会触发 Paint 事件。如果 Paint 事件处理程序中又调用了 Invalidate,就会形成一个循环,导致递归调用 Paint 事件,这

OpenHarmony 主窗体和子窗体的关系

在鸿蒙(HarmonyOS)应用开发中,主窗体和子窗体之间的关系,以及它们与整个应用能力的关系,是层级性结构性的,可以从以下几个方面理解: Window: 当前窗口实例,窗口管理器管理的基本单元。WindowStage: 窗口管理器。管理各个基本窗口单元。 主窗体与子窗体的关系: 定义: 主窗体:应用启动时默认展示的界面,通常对应于应用的主能力。子窗体:在应用中可以被主窗体或其他子窗体打

C# 自定义传值窗体-适合多参数传值

将子窗体的值回传到父窗体中,或者最简单的需要一个设置参数的对话框,其作用也就是得到其中的参数。下面我们详细介绍实现的过程。 文章目录 一、定义一个事件类二、在参数窗体中定义事件三、订阅事件消息 一、定义一个事件类 首先,我们必须定义一个事件,父窗体可以订阅这个事件,并在事件触发时获取参数。下面是如何修改代码来实现这个功能: 首先,定义一个事件参数类和事件: public c

学习【C# Windows窗体】:获得进程的输出

前言 在之前的博客《创建能启动其他程序的Windows窗体》中,我启动了一个其他程序的进程。而进程的输出都显示在控制台窗口中。我在想,可否能读取这些输出,这样就可以配合一些界面显示了,例如约定一个表示进度的信息,来指导进度条的值,这虽然不怎么稳定,但是如果运行的程序也是由自己维护的,那这种方式我觉得没什么不妥。 查了一些资料之后,我发现读取进程的输出很简单(学习的过程中我参考了C#Process

学习【C# Windows窗体】:基础

前言 我发现C# Windows窗体很适合做一些小工具,这些小工具就算做的事情很简单,却也真的能节省使用者的时间与精力。而且,在我看来它有很大的优点: 使用简单拥有图形化的编辑界面可以带参数调用exe,使其泛用性很强。没有特别的运行环境要求(意思是说不用再安装什么额外的东西,只要求一个Windows) 在之前的博客《创建能启动其他程序的Windows窗体》中,我尝试建立一个最简单的,能启动其

030集——自动弹出对话框、选择文件并播放wav音频文件(winform窗体)——C#学习笔记

如图所示,效果如下: 步骤如下: 新建一个winform窗体,双击界面,进入代码区: 复制(下面代码中命名空间内的代码)到(你的命名空间下),运行。 using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Draw

delphi : 窗体的close,free,destroy的区别

一、我用application.create(TForm2,Form2)语句,创建了Form2,可是调用了Form2.close后,重新调用Form2.show. 刚才所创建的Form2仍然存在。问为了节约资源,应该怎样使用close,free,destroy. 三者的关系是什么? 1、Action:=caFree。 2、 with TForm1.Create(Application) do

关于QWidget和QDialog窗体居中的问题

最近开发中,遇到了窗体不能居中的问题,看了网上的很多文章,窗口居中,无非都是move至窗口的中心目标; 有两种方式, 一种在构造函数中直接计算中心坐标; 另一种是在窗口show后再move至相应坐标。但是自己在构造函数中添加了对应的句子以后,窗体不在窗口的(0,0)点显示,反而在右下角显示,自己很是郁闷。网上的两种方法,基本操作如下: 方法一:在窗口(QWidget类及派生类)的构造函数中

QT窗体Widget使用的若干问题

这里介绍的是widget 窗体的属性 最完整的属性请查看qt自带的帮助文档,这里之拿了一部分做说明 窗体属性: object name:物件名称 qwidget:enable 使能本部件 geometry:窗口位置和大小设置 sizepolicy: 1. Fixed: 大小不能改变 2. Minimum: 已经是最小, 不能再被缩小, 但