大手大脚之子类化问题

nlstone 2004-07-09 07:39:52
响应BLUEBOHO,现在开始提问:
什么是子类化?原理?分哪几类?有哪些应用?具体实例?
特别的,什么是窗口的子类化?有哪几种实现方法?实例?
...全文
281 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
星辰游侠 2005-03-18
  • 打赏
  • 举报
回复
mark
会思考的草 2004-07-25
  • 打赏
  • 举报
回复
仅仅是修改了目标窗口的窗口函数而已。
MFC的子类化宏,调用了SDK的API来实现的。
SDK的API就是指GetWindowLong/SetWindowLong这一对函数。
nlstone 2004-07-25
  • 打赏
  • 举报
回复
结贴前最后一顶,还没有出手的快出手啊:)
nlstone 2004-07-12
  • 打赏
  • 举报
回复
感谢大家的精彩论述...
可否对几个没有详述的SUBXXX函数来个简单实例,对了,还有那个超类化...
Kudeet 2004-07-11
  • 打赏
  • 举报
回复
关于子类化的一个比较易懂的解释:

首先,我们看看这个C++程序:
#include <iostream>
using namespace std;
class Parent
{
public:
void func { cout << "Parent" << endl; }
};
class Child : public Parent
{
public:
void func { cout << "Child" << endl; }
};
void main()
{
Parent p;
Child c;
p.func();
c.func();
}
  现在我来解说一下。这段代码中我定义了两个C++类:父类和子类,并且子类是继承自父类的;它们有一个具有相同名称的成员函数func。在main函数中,我分别构造了父类和子类的对象,并调用了它们各自的成员函数func。结果如下:
Parent
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再次回到原来的回调过程中完成剩余的工作。
  以上就是窗口子类化的原理分析,下面我通过一个实例来实际解说如何对窗口进行子类化。当我们需要一个特殊的Edit来限制浮点数的输入,但是现有的Edit却并不能完成这项工作——因为它只能够单纯的限制大小写或者纯数字。就可以采用“子类化”。

  下面我开始按步骤完成对这两个窗口的子类化:
  第一步,在主窗口对话框初始化的时候,保存原有的窗口过程,并设置新的窗口过程。代码如下:
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以及退格键(注意不要少了退格键,否则你将会发现你的编辑框无法删除输入错误的数字)的时候,就发出一声声音以提示输入错误。至于其它的消息,则调用原有的回调函数进行处理。
北狐狸 2004-07-11
  • 打赏
  • 举报
回复
up
Leanderhe 2004-07-10
  • 打赏
  • 举报
回复
问题清楚了一点点!!继续革命!
lianglp 2004-07-10
  • 打赏
  • 举报
回复
简单的说子类化就是把控件的消息处理行为由系统的默认处理转变成自己
处理的行为,比如说WM_LBUTTONDBLCLK,默认系统自己处理,子类化后你可以挂接
这个消息由自己来处理它的行为,比如说当双击时跳出一个对话框,等等。
它的转变方式是SetWindowLong(hwnd,GWL_WNDPROC,(long)subclassproc)具体可以参看
MSDN里面的用法。
MFC里的可以用SubclassWindow()或SubclassDlgItem()进行子类化,当然也可以用
SetWindowLong()进行,前两者都调用后面一个。
huaboy408 2004-07-10
  • 打赏
  • 举报
回复
作为一个程序员,我们经常会在程序中用到Windows通用控件。比如按钮控件,进度条控件等等。但是有时我们需要给控件更多的特色,这就需要做控件的子类化(subclassing).

子类化一个Windows控件与子类化一个C++类不同,子类化一个控件要求你把一个窗口的一些或所有的消息映射都替换成自己的函数来响应,这样你就有效的阻止了控件去做系统默认的行为,而按自己的想法去做。子类化有两种类型: 实例子类化(instance subclassing)和全局子类化(global subclassing)。实例子类化是子类化一个窗口中的单一实例,全局子类化是把整个窗口子类化为一个特殊的类型。这里我们仅讨论单一实例子类化。

记住CWnd派生类对象与窗口本身(一个HWND)的差别是很重要的。你的C++ CWnd-派生类对象包含了一个指向HWND的成员函数,并且包含了当处理消息时HWND消息泵的响应函数(比如WM_PAINT, WM_MOUSEMOVE)。但你用一个C++对象子类化一个窗口时,你就把HWND与C++对象关联起来,并且设置了处理消息时把自定义的回调函数提供给HWND消息使用。

http://www.vccode.com/file_show.php?id=2026
月吻长河 2004-07-10
  • 打赏
  • 举报
回复
以前没听说过
学习
pomelowu 2004-07-09
  • 打赏
  • 举报
回复
汗楼上的广告~~~陌生人继续讲,我仔细在接收。
wengecore 2004-07-09
  • 打赏
  • 举报
回复
欢迎使用CSDN浏览器,可以自如的用符号写大字:
http://pay500.com/s/s51807.htm

该软件是一款方便实用的浏览器,能够方便的浏览中国程序员网站(CSDN)。它拥有各种辅助浏览CSDN帖子的功能,像是一款朴素版的MyIE,但是是专门为浏览CSDN论坛量身定制的。作为程序员来讲,拿这个工具当作浏览器来用都不为过,因为它拥有IE的所有主干功能。
这个软件的视觉设计宗旨就是“朴素、直接、简单、实用”.

界面图:
http://www.pdriver.com/bbs5/UploadFile/200462623482085294.jpg
http://www.pdriver.com/bbs5/UploadFile/20047421335127760.jpg
http://www.pdriver.com/bbs5/UploadFile/20047421395968710.jpg
它能够成为所有软件工作者的好伴侣。
Kudeet 2004-07-09
  • 打赏
  • 举报
回复
子类化的限制:因子类化是对已存在的某一窗口产生作用,所以其作用范围只有这一窗,又由于可能不清楚该类怎样使用额外的类和窗口字节,所以不能保证正确使用这些空间存储信息,最后,因窗口已存在,所以新的窗口过程永远不会接收到第一个WM_CREATE消息或其他以前的消息。子类化只适用于改变极少数窗口行为和属性时使用。
Kudeet 2004-07-09
  • 打赏
  • 举报
回复
Windows是一个基于消息的系统,消息在Windows的对象之间进行着传递。子类化和Windows的钩子机制存在于消息系统之中,我们可以利用这些机制来操纵、修改甚至丢弃那些在操作系统或是进程中传递的消息,以求改变系统的一些行为。

子类化技术用来截取窗口或控件之间的消息,当然是消息在到达目的窗口之前完成的操作。这些被截获的消息既可以保留也可以修改它们的状态,之后就继续发送到目的地。子类化技术实现了一些正常情况下无法实现的功能,试想鼠标右键单击TextBox,系统默认弹出Undo、Cut、Copy、Paste等菜单,我们就可以利用子类化技术来改变这个系统菜单。

简单的说,子类化就是创建一个新的窗口消息处理过程,并将其插入到原先的默认窗口消息处理过程之前。

子类化分为三类:实例子类化(instance subclassing)—从窗口或控件的单一实例截获消息,这种子类化技术最普遍;全局子类化(global subclassing)—能够截获从相同的窗口类创建出来的多个窗口或控件的消息;超类化(superclassing)—和全局子类化很类似,区别在于可以应用在新的窗口类上面。
名牌大灰狼 2004-07-09
  • 打赏
  • 举报
回复
子类?有没有人说说子类的概念呀
Kudeet 2004-07-09
  • 打赏
  • 举报
回复
帖点看到的:不记得地方老

窗口的子类化:

子类化允许我们改变一个已经存在的窗口的行为,我们经常用它来改变控件的行为。它的实现机制是插入一个消息映射表来截取发向控件的消息。举例说明:假设有一个对话框,对话框上有一个编辑框控件,我们想让这个控件只接受不是数字的字符。我们可以截获发往这个控件的WM_CHAR消息并抛弃接收到的数字字符。下面的类实现这个功能: class CNoNumEdit: public CWindowImpl< CNoNumEdit >
{
BEGIN_MSG_MAP( CNoNumEdit )
MESSAGE_HANDLER( WM_CHAR, OnChar )
END_MSG_MAP()

LRESULT OnChar( UINT, WPARAM wParam, LPARAM, BOOL& bHandled )
{
TCHAR ch = wParam;
if( _T(''0'') <= ch && ch <= _T(''9'') )
MessageBeep( 0 );
else
bHandled = FALSE;
return 0;
}
};

这个类只处理一个消息WM_CHAR,如果这个字符是数字的话,则调用MessageBeep( 0 )并返回,这样可以有效地忽略这个字符。如果不是数字,则将bHandled设置为FALSE,指明默认的窗口过程这个消息需要进一步处理。

现在我们将子类化一个编辑框控件,以便CnoNumEdit能够抢先处理发到这个编辑框得消息。(下面得例子用到了CdialogImpl类,这个类我们将在ATL中的对话框类一节中介绍。)在这个例子中,CmyDialog类中用到了一个对话框资源(ID号为IDD_DIALOG1),对话框中有一个编辑框控件(ID号为IDC_EDIT1),当对话框初始化的时候,编辑框经过SubclassWindow而变成一个不接受数字的编辑框: class CMyDialog: public CDialogImpl<CMyDialog>
{
public:
enum { IDD = IDD_DIALOG1 };
BEGIN_MSG_MAP( CMyDialog )
MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
END_MSG_MAP()

LRESULT OnInitDialog( UINT, WPARAM, LPARAM, BOOL& )
{
ed.SubclassWindow( GetDlgItem( IDC_EDIT1 ) );
return 0;
}

CNoNumEdit ed;
};

nlstone 2004-07-09
  • 打赏
  • 举报
回复
up一下,方便查阅...

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧