在开发图形界面(GUI)程序时,对于无句柄的图形控件的框架,在编写响应消息的代码时,可以采用虚函数的方法,在界面框架基类里面调用这些函数,而在子类重写这些虚函数,就可以得到消息的响应。但是,由于windows的消息众多,对应需要编写的虚函数就有很多,这样无疑加大了资源开销,效率也降低。而在MFC消息映射框架里,没有使用虚函数,而是使用了一大堆宏,减少了内存开销,提高了效率。本文提取了MFC消息映射框架,将窗口(CWnd)换成自己的图元(Element),实现了与MFC相同形式的消息映射。
在本代码中,Element是所有界面元素的基类,地位相当与MFC的CWnd。
消息响应函数类型定义的枚举:
enum ESig
{
ESig_end = 0,
// [marks end of message map]
ESig_b_D_v,
// BOOL (CDC*)
ESig_b_b_v,
// BOOL (BOOL)
ESig_b_u_v,
// BOOL (UINT)
ESig_b_h_v,
// BOOL (HANDLE)
ESig_b_W_uu,
// BOOL (CWnd*, UINT, UINT)
ESig_b_W_COPYDATASTRUCT,
// BOOL (CWnd*, COPYDATASTRUCT*)
ESig_b_v_HELPINFO,
// BOOL (LPHELPINFO);
ESig_CTLCOLOR,
// HBRUSH (CDC*, CWnd*, UINT)
ESig_CTLCOLOR_REFLECT,
// HBRUSH (CDC*, UINT)
ESig_i_u_W_u,
// int (UINT, CWnd*, UINT) // ?TOITEM
ESig_i_uu_v,
// int (UINT, UINT)
ESig_i_W_uu,
// int (CWnd*, UINT, UINT)
ESig_i_v_s,
// int (LPTSTR)
ESig_l_w_l,
// LRESULT (WPARAM, LPARAM)
ESig_l_uu_M,
// LRESULT (UINT, UINT, CMenu*)
ESig_v_b_h,
// void (BOOL, HANDLE)
ESig_v_h_v,
};
这里只列举了部分响应函数类型。
基类消息映射函数回调函数定义:
typedef void (Element::*pEMsgFun)(void);
消息映射入口结构体,各个域的含义与MFC类似。
struct EMsgMap_Entery
{
UINT nMessage;
UINT nCode;
UINT nID;
UINT nLastID;
UINT_PTR nSig;
pEMsgFun pfn;
};
消息映射列表结构体。
struct EMsgMap
{
const EMsgMap* (*pfnGetMessageMap)();
const EMsgMap_Entery* lpEnteries;
};
消息映射声明与定义。
#define BEGIN_EMSG_MAP(theClass)\
const EMsgMap* theClass::GetMessageMap() const\
{ return GetThisMessageMap(); }\
const EMsgMap* theClass::GetThisMessageMap()\
{\
typedef theClass ThisClass;\
static const EMsgMap_Entery _messageEntries[]=\
{
#define END_EMSG_MAP()\
{0, 0, 0, 0, ESig_end, (pEMsgFun)0}\
};\
static const EMsgMap messageMap=\
{ 0, &_messageEntries[0] };\
return &messageMap;\
\
}
部分已经实现的消息映射。
#define ON_EM_PAINT() \
{ WM_PAINT, 0, 0, 0, ESig_vv, \
(pEMsgFun) \
(static_cast< void (Element::*)(void) > ( &ThisClass :: OnPaint)) },
#define ON_EM_LBUTTONDOWN()\
{WM_LBUTTONDOWN, 0, 0, 0, ESig_vwp,\
(pEMsgFun)\
(static_cast<void(Element::*)(UINT, POINT)>(&ThisClass::OnLButtonDown))},
#define ON_EM_LBUTTONUP() \
{ WM_LBUTTONUP, 0, 0, 0, ESig_vwp, \
(pEMsgFun) \
(static_cast< void ( Element::*)(UINT, POINT) > ( &ThisClass :: OnLButtonUp)) },
#define ON_EM_MOUSEMOVE() \
{ WM_MOUSEMOVE, 0, 0, 0, ESig_vwp, \
(pEMsgFun) \
(static_cast< void ( Element::*)(UINT, POINT) > ( &ThisClass :: OnMouseMove)) },
#define ON_EM_MOUSELEAVE() \
{ WM_MOUSELEAVE, 0, 0, 0, ESig_vv, \
(pEMsgFun) \
(static_cast< void (Element::*)(void) > ( &ThisClass :: OnMouseLeave)) },
#define ON_EM_SIZE() \
{ WM_SIZE, 0, 0, 0, ESig_vwii, \
(pEMsgFun) \
(static_cast< void ( Element::*)(UINT, int, int) > ( &ThisClass :: OnSize)) },
#define efx_msg
消息处理过程函数,只实现了部分。
LRESULT Element::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )
{
const EMsgMap* pMsgMap = GetMessageMap();
if (pMsgMap == NULL)
return false;
const EMsgMap_Entery* pEntry = pMsgMap->lpEnteries;
int i = 0;
while(pEntry[i].nSig != ESig_end)
{
if (pEntry[i].nMessage == uMsg)
{
switch(pEntry[i].nSig)
{
case ESig_vwp:
{
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
(this->*(reinterpret_cast<void(Element::*)(UINT, POINT)>(pEntry[i].pfn)))((UINT)wParam, pt);
break;
}
case ESig_vv:
{
(this->*(reinterpret_cast<void(Element::*)()>(pEntry[i].pfn)))();
break;
}
case ESig_vwii:
{
(this->*(reinterpret_cast<void(Element::*)(UINT, int, int)>(pEntry[i].pfn)))((UINT)wParam, LOWORD(lParam), HIWORD(lParam));
break;
}
default:
;
}
}
i++;
}
return 1;
}
使用方法。
声明:
class Element
{
//
DECLARE_EMSG_MAP();
//
protected:
efx_msg
void OnPaint();
efx_msg
void OnMouseMove(UINT nFlag, POINT pt);
efx_msg
void OnMouseLeave();
efx_msg
void OnLButtonDown(UINT uFlag, POINT pt);
efx_msg
void OnLButtonUp(UINT uFlag, POINT pt);
//
};
实现:
BEGIN_EMSG_MAP(Element)
//{
ON_EM_PAINT()
ON_EM_MOUSEMOVE()
ON_EM_MOUSELEAVE()
ON_EM_LBUTTONDOWN()
ON_EM_LBUTTONUP()
//}
END_EMSG_MAP()
void Element::OnMouseMove( UINT nFlag, POINT pt )
{
TRACE(TEXT("%ld::Element::OnMouseMove"), this);
}
void Element::OnMouseLeave()
{
TRACE(TEXT("%ld::Element::OnMouseLeave"), this);
}
void Element::OnLButtonDown( UINT uFlag, POINT pt )
{
TRACE(TEXT("%ld::Element::OnLButtonDown"), this);
}
void Element::OnLButtonUp( UINT uFlag, POINT pt )
{
TRACE(TEXT("%ld::Element::OnLButtonUp"), this);
}
这样可以按照以上的思路,不断完善消息映射函数类型。
由于Element是无窗口的图元元素,没有系统的窗口消息的分发支持,所以要想真正实现这些功能,还需要一个图元管理器,用于度量的坐标,消息的分发等等。
posted on 2015-01-11 20:00
weigtcs 阅读(189)
评论(0) 编辑 收藏 引用