DirectUI实现原理

一,概念 

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

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

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

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

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

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

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

二,消息分发过程

以一个窗口基类CWindowWnd为例,注册窗口时,调用这个类的成员函数
[cpp] view plaincopy
 
  1. bool RegisterWindowClass();  

注册时指定窗口处理函数

[cpp] view plaincopy
 
  1. static LRESULT CALLBACK __WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);  

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

[cpp] view plaincopy
 
  1. HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle,   
  2.     DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)  
  3. {  
  4.     if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;  
  5.     if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;  
  6.   
  7.     m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName,   
  8.         dwStyle, x, y, cx, cy, hwndParent, hMenu,   
  9.         CPaintManagerUI::GetInstance(), this);  
  10.   
  11.     ASSERT(m_hWnd!=NULL);  
  12.     return m_hWnd;  
  13. }  

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

[cpp] view plaincopy
 
  1. LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     CWindowWnd* pThis = NULL;  
  4.     if( uMsg == WM_NCCREATE ) {  
  5.         LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);  
  6.         pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);  
  7.         pThis->m_hWnd = hWnd;  
  8.         ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));  
  9.     }   
  10.     else {  
  11.         pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));  
  12.         if( uMsg == WM_NCDESTROY && pThis != NULL ) {  
  13.             LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);  
  14.             ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);  
  15.             if( pThis->m_bSubclassed ) pThis->Unsubclass();  
  16.             pThis->m_hWnd = NULL;  
  17.             pThis->OnFinalMessage(hWnd);  
  18.             return lRes;  
  19.         }  
  20.     }  
  21.     if( pThis != NULL ) {  
  22.         //HandleMessage为虚函数  
  23.         return pThis->HandleMessage(uMsg, wParam, lParam);  
  24.     }   
  25.     else {  
  26.         return ::DefWindowProc(hWnd, uMsg, wParam, lParam);  
  27.     }  
  28. }  

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

三、界面绘制过程

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

[cpp] view plaincopy
 
    1. void CControlUI::DoPaint(HDC hDC, const RECT& rcPaint)  
    2. {  
    3.     if( !::IntersectRect(&m_rcPaint, &rcPaint, &m_rcItem) ) return;  
    4.   
    5.     // 绘制循序:背景颜色->背景图->状态图->文本->边框  
    6.     if( m_cxyBorderRound.cx > 0 || m_cxyBorderRound.cy > 0 ) {  
    7.         CRenderClip roundClip;  
    8.         CRenderClip::GenerateRoundClip(hDC, m_rcPaint,  m_rcItem, m_cxyBorderRound.cx, m_cxyBorderRound.cy, roundClip);  
    9.         PaintBkColor(hDC);  
    10.         PaintBkImage(hDC);  
    11.         PaintStatusImage(hDC);  
    12.         PaintText(hDC);  
    13.         PaintBorder(hDC);  
    14.     }  
    15.     else {  
    16.         PaintBkColor(hDC);  
    17.         PaintBkImage(hDC);  
    18.         PaintStatusImage(hDC);  
    19.         PaintText(hDC);  
    20.         PaintBorder(hDC);  
    21.     }  
    22. }  

http://blog.csdn.net/passion_wu128/article/details/38400535

原文地址:https://www.cnblogs.com/findumars/p/5006173.html