MFC中如何使用拦截消息

拦截消息是可以修改控件或者窗口现有的功能,MFC的子类化技术用C++语言把Windows窗口和各种控件镜像包装,是MFC的核心技术。
以文本框为例,使其只能输入数字。核心原理是一个文本框就是一个窗口,而每一个窗口都有自己的窗口过程。

主要会使用到一下三个函数:

  • SetWindowLong()
    SetWindowLong是一个WindowsAPI函数。该函数用来改变指定窗口的属性.函数也将指定的一个32位值设置在窗口的额外存储空间的指定偏移位置。
  • CallWindowProc()
    CallWindowProc是将消息信息传送给指定的窗口过程的函数。使用函数CallWindowsProc可进行窗口子分类。通常来说,同一类的所有窗口共享一个窗口过程。子类是一个窗口或者相同类的一套窗口,在其消息被传送到该类的窗口过程之前,这些消息是由另一个窗口过程进行解释和处理的
    SetWindowLong函数通过改变与特定窗口相关的窗口过程,使系统调用新的窗口过程来创建子类,新的窗口过程替换了以前的窗口过程。应用程序必须通过调用CallWindowsProc来将新窗口过程没有处理的任何消息传送到以前的窗口过程中,这样就允许应用程序创建一系列窗口过程。
  • SetProp的作用是让系统给你的窗口额外分配一定的空间,用来存储一些你自己定义的数据。打个比方,这就好比是银行的保险箱(Windows显然比银行大方得多,这个是不收费的),第一个参数HWND
    hWnd指定了在哪家银行,第二个参数LPCSTR lpString指定了是哪个保险箱,至于第三个参数HANDLE
    hData则是你要存放的东西。调用SetProp之后,系统就把你提交的那个hData帮你保存起来了,如果某个时候你想要用了,就用GetProp再取出来。如同银行一样,系统是不会管你交给他保存的是什么东西、有什么用处的,它只限定你交给它的东西的体积不能超过保险箱的尺寸,至于怎么使用是你自己的事情

以下示例:

1、首先在输入框中拖入文本编辑控件
2、添加一个新的类,这个类是用来实现控件功能的类
在这个类的头文件中添加一下函数:

#pragma once
class CDloubleEdit
{
public:
	CDloubleEdit();
	~CDloubleEdit();

	BOOL Attach(HWND hWnd); //子类化的嫁接函数,用来将控件的句柄和这个类对象连接起来
	void Detch();//子类化的释放函数,在关闭窗口或者析构的时候,释放句柄
	BOOL GetStringValue(LPTSTR lpBuffer,int nLen);//获取文本控件的输入字符
	BOOL GetDoubleValue(double *pValue);//
protected:
	static LRESULT APIENTRY NewEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
	//这个函数是在使用setWindowsLong函数的时候,新建的控件过程。消息首先会通过此函数。

protected:
	HWND m_hWnd;//用来接收控件句柄
	long m_lOldProc;//永磊接收上一个过程
};

3、在新建类的.cpp函数中实现功能。
(1)在嫁接函数中使用SetWindoslong()函数创建新的过程。
(2)NewEditProc实现函数新增的功能


#include "stdafx.h"
#include "DloubleEdit.h"
#define DOUBLE_EDIT_PROP_NAME _T("Double_EDit_Prop_Name")

CDloubleEdit::CDloubleEdit()
{
}


CDloubleEdit::~CDloubleEdit()
{
	Detch();
}
BOOL CDloubleEdit::Attach(HWND hWnd)
{
	if (m_hWnd != NULL)//判断句柄是不是为空
	{
		DebugBreak();
		return false;
	}
	m_hWnd = hWnd;
	//SetProp:该函数在指定窗口的属性表中增加一个新项,
	//或者修改一个现有项。如果指定的字符串不在属性表中,那么就增加该新的项,
	//新项中包含该字符串和句柄,否则就用指定的句柄替换该字符串的全前句柄。  
	SetProp(hWnd,DOUBLE_EDIT_PROP_NAME,this);//用一个字符串通过SetProp函数,将this(本类)的对象以属性的范式保存
	m_lOldProc = SetWindowLong(hWnd,GWL_WNDPROC,(long)NewEditProc);//创建新的过程
	if (m_lOldProc == 0)
	{
		m_lOldProc = NULL;
		return false;
	}
	else
	return TRUE;
}
LRESULT APIENTRY CDloubleEdit::NewEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	CDloubleEdit* pEdit = (CDloubleEdit*)GetProp(hWnd,DOUBLE_EDIT_PROP_NAME);
	if (pEdit == NULL)
	{
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	
	BOOL bCanceled = FALSE;
	if (uMsg == WM_CHAR)
	{
		TCHAR szBuf[32] = { 0 };
		pEdit->GetStringValue(szBuf, 32);
	switch (wParam)
		{
		case '.':
			if (_tcschr(szBuf,'.'))
			{
				bCanceled = TRUE;
			}
			break;
		case '_':
			if (_tcschr(szBuf, '_'))
			{
				bCanceled = TRUE;
			}
			else if (LOWORD(SendMessage(hWnd, EM_GETSEL, 0, 0)) != 0)
			{
				bCanceled = FALSE;
			}
			break;
		default:
			if (wParam>'9' || wParam <'0')
			{
				bCanceled = TRUE;
			}
			break;
		}
		if (bCanceled)
		{
			MessageBeep(-1);
			return 0;
		}
	}
	return CallWindowProc((WNDPROC)pEdit->m_lOldProc, hWnd, uMsg, wParam, lParam);

}
BOOL CDloubleEdit::GetStringValue(LPTSTR lpBuffer, int nLen)
{
	return GetWindowText(m_hWnd,lpBuffer,nLen);
}
BOOL CDloubleEdit::GetDoubleValue(double *pValue)
{
	TCHAR szBuf[32];
	if (GetStringValue(szBuf, 32))
	{
		*pValue = atof((const char*)szBuf);
		return TRUE;
	}
	else
		return FALSE;
}
void CDloubleEdit::Detch()
{

	if (m_hWnd == NULL)
	{
		return;
	}
	SetWindowLong(m_hWnd, GWL_WNDPROC, m_lOldProc);
	m_hWnd = NULL;
	m_lOldProc = 0;
}

4、在对话框的实现类中添加新建类的对象,调用新建类的attch函数嫁接文本编辑框的句柄。

CDloubleEdit g_edit;
g_edit.Attach(GetDlgItem(IDC_EDI_INPUT)->GetSafeHwnd());

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值