PreSubclassWindow()

本文详细介绍了如何通过子类化窗口来实现对已有窗口的定制功能,如输入检测等。文章解释了子类化的基本原理,并提供了具体实现步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CWnd::PreSubclassWindow
virtual void PreSubclassWindow( );
说明:
框架调用这个成员函数以允许在窗口被 子类化之前进行其它必要的子类化。 重载这个函数以允许控件的动态 子类化。这是个高级可 重载函数
如果你曾经在 Windows 环境下编过程序,有时候就会发现:有一个现成的窗口,几乎有你所需要的全部功能,但还不完全一样。如果你需要一个具有过滤特殊字符功能的 Edit 控件。当然最直接的方法就是自己用代码来实现,但这的确是一个费时又很困难的任务,而子类化就可以用来做这种事情。

目录

子类化
说明

编辑本段子类化

子类化允许你接管被子类化的窗口,使你对它有绝对的控制权。举个例子了来阐明一下:例如你需要一个只接受十六进制数字输入的文本编辑框,如果使用一个简单的 Edit控件,当用户输入十六进制以外的字符时,你既不知道也无计可施。也就是说,当用户进 文本框中输入字符串 "zb+q*" 时,如果除了拒绝接受整个字符串以外几乎什么也不能做,至少这显得特别不专业。重要的是,你需要具有输入检测的能力,即每当用户输入一个字符到编辑框中时要能检测这个字符。
现在来解释实现细节:当用户往 文本框中输入 字符时,Windows 会给Edit控件的 窗口函数发送 WM_CHAR 消息。这个 窗口函数本身寄生于 Windows 中,因此不能直接修改它。但是我们可以重定向这个消息使之发送到我们自己编写的窗口处理函数。如果自定义窗口要处理这个消息那就可以处理它,如果不处理就可以把这个消息转发到它原来窗口处理函数。通过这种方式,自定义的窗口处理函数就把它自己插入到 Windows 系统和 Edit 控件之间。

编辑本段说明

看下面的流程:
窗口子类化之前
Windows ==>Edit 控件的窗口处理函数。
子类化之后
Windows ==>自定义的窗口处理函数==> Edit 控件的窗口处理函数。
注意子类化并不局限于控件,可以子类化任何窗口,现在我们要把精力集中到怎样实现子类化一个窗口上。让我们想想Windows 怎样知道 Edit 控件的窗口处理函数放在什么地方。猜的?…肯定不是。原来 WNDCLASSEX 结构的成员 lpfnWndProc 指出了 窗口函数地址。如果能用自己编写的 窗口函数的地址来替换这个 成员变量,那 Windows 不就把消息发到自定义的窗口函数了吗! 我们通过调用函数SetWindowLong 来实现这个任务,此函数的原型为:
SetWindowLong PROTO hWnd:DWORD, nIndex:DWORD, dwNewLong:DWORD
hWnd = 将要实施子类化的窗口的句柄 nIndex = 函数的功能索引
GWL_EXSTYLE 设置窗口的扩展风格.
GWL_STYLE 设置新的窗口风格
GWL_WNDPROC 设置新的窗口处理函数地址
GWL_HINSTANCE 设置新的应用程序句柄
GWL_ID 设置新的窗口标识
GWL_USERDATA 设置一个与这个窗口相关的给用户使用的32位的数据 dwNewLong = 用来更新的数据 我们的工作还是比较简单的:
写一个窗口函数用于处理发给 Edit 控件的消息。 用参数GWL_WNDPROC调用SetWindowLong 函数,如果调用成功那么返回值就是与调用功能相联系的一个32位的整数 在我们的程序中,返回值就是原先 窗口函数的地址。我们要保存这个值以便以后使用。 记住:有一些我们不处理的消息,需要把它们派遣给原来的 窗口函数来处理,这就用到另外一个函数 CallWindowProc, 函数原型为:
CallWindowProc PROTO lpPrevWndFunc:DWORD, hWnd:DWORD, Msg:DWORD, wParam:DWORD, lParam:DWORD
lpPrevWndFunc = 窗口原来函数的地址. 剩下的四个参数就是发给自定义函数的参数,直接把它们传给函数 CallWindowProc 就行了。

### 修改MFC ComboBox控件的字体 在MFC应用程序中,可以通过重载`PreSubclassWindow`成员函数或处理WM_SETFONT消息来改变ComboBox控件使用的字体。以下是具体的方法: #### 方法一:通过重写 `PreSubclassWindow` 当派生自己的组合框类时,在其中覆盖`PreSubclassWindow()`方法,并在此处设置新的字体属性。 ```cpp void CMyComboBox::PreSubclassWindow() { CFont* pOldFont = GetFont(); LOGFONT lf; if(pOldFont != NULL && pOldFont->GetObject(sizeof(lf), &lf)) { // 自定义字体参数 _tcscpy_s(lf.lfFaceName, _T("Arial")); lf.lfHeight = -MulDiv(12, ::GetDeviceCaps(GetDC()->m_hDC, LOGPIXELSY), 72); // 设置字号为12pt CFont font; font.CreateFontIndirect(&lf); SetFont(&font); } __super::PreSubclassWindow(); } ``` 此段代码展示了如何创建一个新的字体对象并将它应用到组合框上[^1]。 #### 方法二:响应 WM_SETFONT 消息 另一种方式是在对话框资源文件中指定一个特定风格的字体给整个窗口,或者单独针对某个控件发送WM_SETFONT消息以更新其外观。 ```cpp afx_msg void OnSetFont(CWnd *pWnd, BOOL bRedraw) { CDC* pDc = this->GetDC(); TEXTMETRIC tm; pDc->GetTextMetrics(&tm); CString strFontName(_T("Courier New")); int nFontSize = MulDiv(-12, pDc->GetDeviceCaps(LOGPIXELSX), 72); LOGFONT logFont = {0}; logFont.lfHeight = nFontSize; logFont.lfWeight = FW_NORMAL; logFont.lfCharSet = ANSI_CHARSET; lstrcpy(logFont.lfFaceName,strFontName); CFont myFont; VERIFY(myFont.CreateFontIndirect(&logFont)); SendMessage(WM_SETFONT,(WPARAM)myFont.m_hObject,bRedraw); } ``` 上述例子中,构造了一个名为`OnSetFont`的消息处理器用于接收来自父级容器传递过来的新字体信息,并据此调整当前组件所呈现的文字效果[^4]。 对于希望在整个应用程序范围内统一管理字体样式的开发者来说,还可以考虑将这些逻辑封装成独立的帮助函数或是基类的一部分以便重复利用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值