DirectUI实现原理

 一,概念 

传统的Windows窗口程序对每一个控件都会创建一个句柄,而DUI技术奖所有控件都绘制在一个窗体上,这些控件的逻辑和绘图方式必须自己进行编写和封装,所以这些控件都是无句柄的。

DUI技术的实现步骤和难点:

1,窗口的子类化,截获窗口的消息。

2,封装自己的控件,并将自己的控件绘制到该窗口上。

3,封装窗口的消息,并分发到自己的控件上,让自己的控件响应消息。

4,根据不同的行为发送自定义消息给窗口,比便程序进行调用。

5,一般窗口上控件的组织使用XML来描述。

二,消息分发过程

以一个窗口基类CWindowWnd为例,注册窗口时,调用这个类的成员函数
 bool RegisterWindowClass();

注册时指定窗口处理函数

 static LRESULT CALLBACK __WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

然后再以一个成员函数创建窗口

HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, 
	DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
{
    if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
    if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;

    m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, 
		dwStyle, x, y, cx, cy, hwndParent, hMenu, 
		CPaintManagerUI::GetInstance(), this);

    ASSERT(m_hWnd!=NULL);
    return m_hWnd;
}

创建时将this指针传入到CreateWindowEx的最后一个参数。响应WM_NCCREATE消息时就能取到this指针的值,进而调用虚函数,子类重写这个虚函数就能实现不同的消息处理。

LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CWindowWnd* pThis = NULL;
    if( uMsg == WM_NCCREATE ) {
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
        pThis->m_hWnd = hWnd;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
    } 
    else {
        pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
        if( uMsg == WM_NCDESTROY && pThis != NULL ) {
            LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
            ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
            if( pThis->m_bSubclassed ) pThis->Unsubclass();
            pThis->m_hWnd = NULL;
            pThis->OnFinalMessage(hWnd);
            return lRes;
        }
    }
    if( pThis != NULL ) {
		//HandleMessage为虚函数
        return pThis->HandleMessage(uMsg, wParam, lParam);
    } 
    else {
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

消息转发过程和传统的Windows程序也不一样。比如在一个传统的窗口上左键点击一个按钮时,将会发送一个WM_COMMAND的消息给窗口,wParam的低字节为按钮ID,高字节为BN_CLICKED,而lParam为按钮句柄。而在DUI里面是怎样的呢?首先系统发送一个WM_LBUTTONDOWN消息给窗口,lParam为点击的坐标信息,根据这个坐标找到相应的按钮。然后将一些必要的信息(比如控件指针,名称,消息类型)组成一个Notify发送给窗口,窗口再根据Notify里面的信息作出相应处理。

三、界面绘制过程

窗口接收到WM_PAINT消息时,先绘制自身,然后根据控件树的组织由Parent节点到Child节点依次绘制。绘制每一个元素时一般是按以下步骤:

void CControlUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
    if( !::IntersectRect(&m_rcPaint, &rcPaint, &m_rcItem) ) return;

    // 绘制循序:背景颜色->背景图->状态图->文本->边框
    if( m_cxyBorderRound.cx > 0 || m_cxyBorderRound.cy > 0 ) {
        CRenderClip roundClip;
        CRenderClip::GenerateRoundClip(hDC, m_rcPaint,  m_rcItem, m_cxyBorderRound.cx, m_cxyBorderRound.cy, roundClip);
        PaintBkColor(hDC);
        PaintBkImage(hDC);
        PaintStatusImage(hDC);
        PaintText(hDC);
        PaintBorder(hDC);
    }
    else {
        PaintBkColor(hDC);
        PaintBkImage(hDC);
        PaintStatusImage(hDC);
        PaintText(hDC);
        PaintBorder(hDC);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值