随笔-6  评论-0  文章-0  trackbacks-0
在开发图形界面(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, intint) > ( &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, intint)>(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 阅读(177) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理