实战经验:ON_CONTROL_REFLECT(_EX)的在CEdit扩展中的使用

实战经验:ON_CONTROL_REFLECT(_EX)的在CEdit扩展中的使用

作者:BlogUpdater |  时间:2019-03-10 |  浏览:3279 |  评论已关闭 条评论

MFC提供了编辑框控件CEdit,可以基本满足我们的一般性编辑需求,但是如果想对CEdit进行定制,例如重新设计其边框,对用户输入做预处理的时候,我们需要扩展CEdit。今天来看看ON_CONTROL_REFLECT和ON_CONTROL_REFLECT_EX这两个反射宏在CEdit扩展中的使用。

ON_CONTROL_REFLECT
从名称上来看,ON_CONTROL_REFLECT是一个反射宏。所谓反射,可以这样理解:通常控件的运行,例如绘制,通知的处理等需要其父窗口来处理,如果希望控件能自己处理一些消息,则需要使用到反射。也即,控件的消息将不会路由到其父窗口,而是直接在控件类里直接得到处理。

以下代码演示了通过ON_CONTROL_REFLECT宏,实现在控件类中直接处理EN_CHANGE消息的过程。

#pragma once

class CMyEdit : public CEdit
{
	DECLARE_DYNAMIC(CMyEdit)

public:
	CMyEdit();
	virtual ~CMyEdit();
	void OnEnChange();

protected:
	DECLARE_MESSAGE_MAP()
};
#include "stdafx.h"
#include "Test.h"
#include "MyEdit.h"

IMPLEMENT_DYNAMIC(CMyEdit, CEdit)

BEGIN_MESSAGE_MAP(CMyEdit, CEdit)
	ON_CONTROL_REFLECT(EN_CHANGE, OnEnChange)
END_MESSAGE_MAP()

CMyEdit::CMyEdit()
{
}

CMyEdit::~CMyEdit()
{
}

void CMyEdit::OnEnChange()
{
	AfxMessageBox(_T("Contorl: OnEnChange"));
}

代码解析
1) 我们的CMyEdit继承自CEdit,并通过编写事件处理函数OnEnChange来处理控件的EN_CHANGE消息。通过ON_CONTROL_REFLECT来将EN_CHANGE消息反射至类本身。
2) 注意,在这种情况下,父窗口将不会收到EN_CHANGE通知,也即,你在父窗口中编写如下的代码,将不会工作。

void CTestDlg::OnEnChangeEdit1()
{
	AfxMessageBox(_T("Parent: OnEnChange"));
}

ON_CONTROL_REFLECT_EX
如果我们希望控件自身处理消息的同时,父窗口也能有机会处理这个消息,则我们可以使用ON_CONTROL_REFLECT_EX宏。
先看代码。

#pragma once

class CMyEdit : public CEdit
{
	DECLARE_DYNAMIC(CMyEdit)

public:
	CMyEdit();
	virtual ~CMyEdit();
	BOOL OnEnChangeEx();

protected:
	DECLARE_MESSAGE_MAP()
};
#include "stdafx.h"
#include "Test.h"
#include "MyEdit.h"

IMPLEMENT_DYNAMIC(CMyEdit, CEdit)

BEGIN_MESSAGE_MAP(CMyEdit, CEdit)
	ON_CONTROL_REFLECT_EX(EN_CHANGE, OnEnChangeEx)
END_MESSAGE_MAP()

CMyEdit::CMyEdit()
{
}

CMyEdit::~CMyEdit()
{
}

BOOL CMyEdit::OnEnChangeEx()
{
	AfxMessageBox(_T("Contorl: OnEnChangeEx"));
	return FALSE;
}

父窗口处理代码

ON_EN_CHANGE(IDC_EDIT1, &CTestDlg::OnEnChangeEdit1)
void CTestDlg::OnEnChangeEdit1()
{
	AfxMessageBox(_T("Parent: OnEnChange"));
}

代码解析
1) 使用了ON_CONTROL_REFLECT_EX宏,而不是ON_CONTROL_REFLECT。这个宏接受的处理函数,需要返回一个BOOL值,如果处理函数返回FALSE,则消息继续路由至父窗口,否则消息仅会在控件内部处理。
2) 我们在父窗口中使用ON_EN_CHANGE,将控件ID和消息处理函数绑定在一起。仅当控件的OnEnChangeEx返回FALSE时,OnEnChangeEdit1才会得到执行。

总结
1) ON_CONTROL_REFLECT(_EX)这个反射宏是个非常有用的工具,适用于控件自定义的场景。
2) 将控件通用的操作及特性通过反射技术封装到控件内部,减少控件与父窗口的代码耦合,即可初步实现一个自包含的控件。这对于客户(父窗口)来说,将会是一个十分友好易用的组件。

标签:

评论已关闭。