DUiLib 源碼分析 ——以UiLib 1.01版為分析目標
----------------------------------------------------------------------------------
分析約定:
private o------- 私有的成員變量或方法
protect x------- 受保護的成員變量或方法
public +------- 公開的成員變量或方法
----------------------------------------------------------------------------------
本篇分析一下源文件
UIManager.h/UIManager.cpp
CPaintManagerUI
成員變量
窗體句柄
o---m_hWndPaint 要CPaintManagerUI進行Direct繪圖操作的窗體句柄
o---m_hwndTooltip 提示窗口句柄
o---m_hInstance 當前管理的Instance實例
o---m_hResourceInstance 當前管理的資源DLL Instance實例
o---m_pStrResourcePath 當前使用的資源路徑
o---m_pStrResourceZip 當前使用的資源壓縮包文件全稱
------------------------------------------------------CPaintManagerUI使用的資源
繪圖設備
o---m_hDcPaint 直接繪制到窗體的DC(為窗體的整個區域包括費客戶區)
o---m_hDcOffscreen 內存緩沖區繪圖DC
o---m_hDcBackground 背景繪制(支持AlphaBackground時使用)
位圖
o---m_hbmpOffscreen m_hDcPaint的后台作圖畫布
o---m_hbmpBackground 背景圖片bmp
------------------------------------------------------CPaintManagerUI用到的信息
o---m_ToolTip 提示消息
typedef struct tagTOOLINFOA {
UINT cbSize; //該結構體的大小 sizeof(TOOLINFO)
UINT uFlags; //附加標識類信息
HWND hwnd; //消息接受的窗體
UINT_PTR uId; //控件ID
RECT rect; //消息產生的區域位置
HINSTANCE hinst; //消息接收的實例
LPSTR lpszText; //提示消息
LPARAM lParam; //IE3.0以上的版本有該屬性
void *lpReserved; //NT5.0以上的版本有該屬性 附加信息
} TOOLINFO
標識類信息
o---m_bShowUpdateRect 是否顯示更新區域
o---m_bFirstLayout 是否是首個布局
o---m_bUpdateNeeded 是否需要更新界面
o---m_bFocusNeeded 是否需要焦點
o---m_bOffscreenPaint 是否需要開雙緩存繪圖
o---m_bAlphaBackground 窗體背景是否需要支持Alpha通道(如png圖片的半透明效果)
o---m_bMouseTracking 是否需要支持鼠標追蹤
o---m_bMouseCapture 是否需要支持鼠標捕獲
控件信息
o---m_pRoot xml根節點解析成的對象,通常為各種Window
o---m_pFocus 處於獲得焦點狀態的控件
o---m_pEventHover 處於鼠標懸停狀態的控件
o---m_pEventClick 被鼠標點擊的控件
o---m_pEventKey 接收鍵盤輸入的控件
位置記錄信息
o---m_pLastMousePos 鼠標最新的位置
o---m_szMinWindow 設置窗體可以調整到的最小大小
o---m_szMaxWindow 窗體可以調整到的最大大小
o---m_szInitWindowSize 窗體初始化是的大小
o---m_rcSizeBox 窗體外邊框區域的大小
o---m_szRoundCorner 窗體四角的圓角弧度
o---m_rcCaption 窗體標題欄區域大小
o---m_uTimerID 當前定時器ID
集合類信息
o---m_aNotifiers 能夠接收通知的對象集合
o---m_aTimers 定時器集合
o---m_aPreMessage 預處理消息集合
o---m_aPreMessageFilters 預處理消息過濾器集合
o---m_aMessageFilters 消息過濾器集合
o---m_aPostPaintControls 發送繪制請求的控件集合
o---m_aDelayedCleanup 延遲清理的對象集合
o---m_aAsyncNotify 異步通知消息集合
o---m_mNameHash 名稱HashMap
o---m_mOptionGroup 選項組Map
xml對應資源
o---m_pParentResourcePM 上級(父類)資源的PaintManagerUI繪圖管理器
o---m_dwDefaultDisabledColor 默認失效狀態顏色
o---m_dwDefaultFontColor 默認字體顏色
o---m_dwDefaultLinkFontColor 默認超鏈接字體顏色
o---m_dwDefaultLinkHoverFontColor默認超鏈接鼠標懸停狀態的字體顏色
o---m_dwDefaultSelectedBkColor 默認選中狀態背景色
o---m_DefaultFontInfo 默認字體信息
TFontInfo{
hFont 該字體的句柄
sFontName 字體名稱
iSize 字號
bBold 是否粗體
bUnderline 是否有下划線
bItalic 是否為斜體
TEXTMETRIC tm 該字體的TEXTMETRIC信息
}
o---m_aCustonFonts 自定義字體資源集合
o---m_mImageHash 圖片資源HashMap
o---m_DefaultAttrHash DefaultAttr資源HashMap
私有方法
將所有的控件添加到m_mNameHash哈希表中
o---static CControlUI* CALLBACK __FindControlFromNameHash(CControlUI* pThis, LPVOID pData);
計算控件數量
o---static CControlUI* CALLBACK __FindControlFromCount(CControlUI* pThis, LPVOID pData);
根據點是否在區域中,查詢控件
o---static CControlUI* CALLBACK __FindControlFromPoint(CControlUI* pThis, LPVOID pData);
通過Tab信息查詢控件
o---static CControlUI* CALLBACK __FindControlFromTab(CControlUI* pThis, LPVOID pData);
從快照中查詢控件
o---static CControlUI* CALLBACK __FindControlFromShortcut(CControlUI* pThis, LPVOID pData);
查找需要更新的控件
o---static CControlUI* CALLBACK __FindControlFromUpdate(CControlUI* pThis, LPVOID pData);
通過名稱比較查詢控件
o---static CControlUI* CALLBACK __FindControlFromName(CControlUI* pThis, LPVOID pData);
公開方法
繪圖管理器的初始化(m_hWndPaint,m_hDcPaint賦值,在預處理消息中加入管理器)
+---void Init(HWND hWnd);
當前需要更新界面
+---void NeedUpdate();
指定區域失效
+---void Invalidate(RECT& rcItem);
獲取繪圖設備DC
+---HDC GetPaintDC() const;
獲取繪圖的窗口句柄
+---HWND GetPaintWindow() const;
獲取提示窗體句柄
+---HWND GetTooltipWindow() const;
獲取當前鼠標的位置
+---POINT GetMousePos() const;
獲取客戶區大小
+---SIZE GetClientSize() const;
獲取窗體初始化時的大小
+---SIZE GetInitSize();
設置窗體初始化大小
+---void SetInitSize(int cx, int cy);
獲取窗體的邊框區域大小
+---RECT& GetSizeBox();
設置窗體的邊框區域大小
+---void SetSizeBox(RECT& rcSizeBox);
獲取標題區域位置
+---RECT& GetCaptionRect();
設置標題區域位置
+---void SetCaptionRect(RECT& rcCaption);
獲取窗體四角的圓角弧度
+---SIZE GetRoundCorner() const;
設置窗體四角的圓角弧度
+---void SetRoundCorner(int cx, int cy);
獲取窗體可以調整到的最小大小
+---SIZE GetMinInfo() const;
設置窗體可以調整到的最小大小
+---void SetMinInfo(int cx, int cy);
獲取窗體可以調整到的最大大小
+---SIZE GetMaxInfo() const;
設置窗體可以調整到的最大大小
+---void SetMaxInfo(int cx, int cy);
窗體的不透明度(0完全透明-255完全不透明)
+---void SetTransparent(int nOpacity);
設置繪圖是否支持透明處理
+---void SetBackgroundTransparent(bool bTrans);
是否顯示更新區域
+---bool IsShowUpdateRect() const;
設置是否顯示更新
+---void SetShowUpdateRect(bool show);
獲取當前管理的實例句柄
+---static HINSTANCE GetInstance();
獲得當前運行的實例的路徑
+---static CStdString GetInstancePath();
獲得當前的工作路徑
+---static CStdString GetCurrentPath();
獲取資源DLL的實例句柄
+---static HINSTANCE GetResourceDll();
獲取資源的路徑(以"\"結尾)
+---static const CStdString& GetResourcePath();
獲得Zip資源的路徑
+---static const CStdString& GetResourceZip();
設置實例句柄
+---static void SetInstance(HINSTANCE hInst);
設置當前的工作路徑
+---static void SetCurrentPath(LPCTSTR pStrPath);
設置當前的DLL資源的實例句柄
+---static void SetResourceDll(HINSTANCE hInst);
設置資源所在文件夾路徑
+---static void SetResourcePath(LPCTSTR pStrPath);
設置Zip資源的路徑(包括Zip文件名)
+---static void SetResourceZip(LPCTSTR pStrZip);
設置使用上級資源的繪圖管理器
+---bool UseParentResource(CPaintManagerUI* pm);
獲得上級資源繪圖管理器
+---CPaintManagerUI* GetParentResource() const;
獲取禁用狀態的默認顏色
+---DWORD GetDefaultDisabledColor() const;
設置禁用狀態的默認顏色
+---void SetDefaultDisabledColor(DWORD dwColor);
獲取字體默認顏色
+---DWORD GetDefaultFontColor() const;
設置字體默認顏色
+---void SetDefaultFontColor(DWORD dwColor);
設置鏈接文字的默認字體顏色
+---DWORD GetDefaultLinkFontColor() const;
獲取鏈接文字的默認顏色
+---void SetDefaultLinkFontColor(DWORD dwColor);
獲取鼠標懸停與超鏈上的默認字體顏色
+---DWORD GetDefaultLinkHoverFontColor() const;
獲取鼠標懸停與超鏈上的默認字體顏色
+---void SetDefaultLinkHoverFontColor(DWORD dwColor);
獲取選中狀體的默認背景顏色
+---DWORD GetDefaultSelectedBkColor() const;
設置選中狀態的默認背景顏色
+---void SetDefaultSelectedBkColor(DWORD dwColor);
獲取默認使用的字體信息
+---TFontInfo* GetDefaultFontInfo();
設置默認使用的字體信息
+---void SetDefaultFont(LPCTSTR pStrFontName, int nSize, bool bBold, bool bUnderline, bool bItalic);
獲取用戶自定義字體的數量(一般對應xml中Font的數量)
+---DWORD GetCustomFontCount() const;
向字體數組列表追加字體資源
+---HFONT AddFont(LPCTSTR pStrFontName, int nSize, bool bBold, bool bUnderline, bool bItalic);
向字體數組列表中插入字體資源
+---HFONT AddFontAt(int index, LPCTSTR pStrFontName, int nSize, bool bBold, bool bUnderline, bool bItalic);
獲取數組中指定下標的字體對象句柄
+---HFONT GetFont(int index);
從字體數組中獲取指定配置的字體對象句柄
+---HFONT GetFont(LPCTSTR pStrFontName, int nSize, bool bBold, bool bUnderline, bool bItalic);
字體數組集合中是否存在字體對象
+---bool FindFont(HFONT hFont);
字體數組集合中是否存在指定配置的字體對象
+---bool FindFont(LPCTSTR pStrFontName, int nSize, bool bBold, bool bUnderline, bool bItalic);
獲得字體對象的
+---int GetFontIndex(HFONT hFont);
根據指定的配置信息查詢字體索引
+---int GetFontIndex(LPCTSTR pStrFontName, int nSize, bool bBold, bool bUnderline, bool bItalic);
從字體數組列表中移除字體對象
+---bool RemoveFont(HFONT hFont);
從字體數組列表中移除指定位置的字體信息
+---bool RemoveFontAt(int index);
清空字體數組列表
+---void RemoveAllFonts();
通過字體數組索引查找字體信息
+---TFontInfo* GetFontInfo(int index);
通過字體對象句柄獲取字體信息
+---TFontInfo* GetFontInfo(HFONT hFont);
根據圖像路徑查找圖像信息
+---const TImageInfo* GetImage(LPCTSTR bitmap);
根據名稱,類型,遮罩色 查詢 圖像信息
+---const TImageInfo* GetImageEx(LPCTSTR bitmap, LPCTSTR type = NULL, DWORD mask = 0);
添加圖像
+---const TImageInfo* AddImage(LPCTSTR bitmap, LPCTSTR type = NULL, DWORD mask = 0);
添加圖像
+---const TImageInfo* AddImage(LPCTSTR bitmap, HBITMAP hBitmap, int iWidth, int iHeight, bool bAlpha);
根據圖像名稱移除圖像
+---bool RemoveImage(LPCTSTR bitmap);
移除全部圖像
+---void RemoveAllImages();
添加控件的默認配置信息(如button)
+---void AddDefaultAttributeList(LPCTSTR pStrControlName, LPCTSTR pStrControlAttrList);
根據控件名稱查詢該類控件的默認配置
+---LPCTSTR GetDefaultAttributeList(LPCTSTR pStrControlName) const;
移除指定控件類型名稱的默認配置
+---bool RemoveDefaultAttributeList(LPCTSTR pStrControlName);
獲取默認配置信息列表
+---const CStdStringPtrMap& GetDefaultAttribultes() const;
清空默認配置信息列表
+---void RemoveAllDefaultAttributeList();
將對話框控件附加到當前的管理器中
+---bool AttachDialog(CControlUI* pControl);
控件初始化
+---bool InitControls(CControlUI* pControl, CControlUI* pParent = NULL);
控件回收
+---void ReapObjects(CControlUI* pControl);
添加控件到指定的選項組
+---bool AddOptionGroup(LPCTSTR pStrGroupName, CControlUI* pControl);
查詢指定選項組名稱中的全部選項
+---CStdPtrArray* GetOptionGroup(LPCTSTR pStrGroupName);
從指定控件中移除指定選項組名稱的選項組
+---void RemoveOptionGroup(LPCTSTR pStrGroupName, CControlUI* pControl);
清空全部選項組列表
+---void RemoveAllOptionGroups();
獲取焦點狀態的控件
+---CControlUI* GetFocus() const;
設置控件為獲得焦點狀態
+---void SetFocus(CControlUI* pControl);
設置控件為需要繪制焦點
+---void SetFocusNeeded(CControlUI* pControl);
設置下一個獲得Tab鍵會獲得焦點的控件,Tab是否繼續往下走
+---bool SetNextTabControl(bool bForward = true);
為指定控件以及其子控件設置定時器
+---bool SetTimer(CControlUI* pControl, UINT nTimerID, UINT uElapse);
移除指定控件上的指定編號的定時器
+---bool KillTimer(CControlUI* pControl, UINT nTimerID);
清空所有的定時器
+---void RemoveAllTimers();
設置窗體接受鼠標事件
+---void SetCapture();
釋放窗體捕獲鼠標事件
+---void ReleaseCapture();
判斷窗體是否接受鼠標事件
+---bool IsCaptured();
添加控件到通知集合中
+---bool AddNotifier(INotifyUI* pControl);
將控件從通知集合中移除
+---bool RemoveNotifier(INotifyUI* pControl);
發送同步/異步通知
+---void SendNotify(TNotifyUI& Msg, bool bAsync = false);
構建同步或異步通知並發送
+---void SendNotify(CControlUI* pControl, LPCTSTR pstrMessage, WPARAM wParam = 0, LPARAM lParam = 0, bool bAsync = false);
向預處理消息過濾器鏈中添加消息過濾器
+---bool AddPreMessageFilter(IMessageFilterUI* pFilter);
從預處理消息過濾器鏈合中移除指定的消息過濾器
+---bool RemovePreMessageFilter(IMessageFilterUI* pFilter);
向消息過濾器鏈中添加消息過濾器
+---bool AddMessageFilter(IMessageFilterUI* pFilter);
從消息過濾器鏈中移除消息過濾器
+---bool RemoveMessageFilter(IMessageFilterUI* pFilter);
獲取發送需要繪制的控件的數量
+---int GetPostPaintCount() const;
向繪制請求集合中添加要繪制的控件
+---bool AddPostPaint(CControlUI* pControl);
從繪制請求集合中移除指定的控件
+---bool RemovePostPaint(CControlUI* pControl);
將繪制請求控件插入到繪制請求集合的指定位置
+---bool SetPostPaintIndex(CControlUI* pControl, int iIndex);
向延遲清理集合中添加需要延遲清理的對象
+---void AddDelayedCleanup(CControlUI* pControl);
獲取根節點控件
+---CControlUI* GetRoot() const;
從根節點開始查找指定點所在的控件
+---CControlUI* FindControl(POINT pt) const;
從指定節點開始查找指定點所在的控件
+---CControlUI* FindControl(CControlUI* pParent, POINT pt) const;
從根節點開始,查找指定名稱的控件
+---CControlUI* FindControl(LPCTSTR pstrName);
從指定節點開始查找指定名稱的控件
+---CControlUI* FindControl(CControlUI* pParent, LPCTSTR pstrName);
消息循環,非游戲框架消息泵,無法利用無消息的空閑時間
+---static void MessageLoop();
消息翻譯,在Win32原有的消息轉換基礎上,將需要自己處理的消息轉發給消息預處理器
+---static bool TranslateMessage(const LPMSG pMsg);
消息預處理器
1.消息預處理過濾(消息預處理過濾器集合對消息進行過濾處理)
2.檢查是否按下Tab鍵,設置下一個獲得焦點的控件
3.處理Alt+Shortcut Key按下后的控件獲得焦點和激活的設置
4.檢查是否有系統鍵消息,有則發送獲得焦點的控件的事件
+---bool PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes);
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
消息處理器(核心處理器)
1.消息過濾
2.檢查Custom消息並處理
3.檢查是否有WM_CLOSE消息並處理
4.處理WM_ERASEBKGND(不允許進行背景擦除,防止閃爍)
5.繪制處理(核心)
5.1做延遲繪圖判斷,當前是否有 窗體大小調整的操作,或者是否需要初始化窗體
5.2設置焦點控件
5.3如果開啟雙緩存繪圖,采用雙緩存方式繪圖,否則采用標准繪圖方式繪圖
5.4
6.處理客戶區的繪制WM_PRINTCLIENT
7.接到WM_GETMINMAXINFO消息后向系統提交該窗體可調整大小的最小和最大限制
8.窗體大小改變時,向焦點控件發送改變大小消息並設置窗體需要更新
9.處理定時器消息,向定時器集合中廣播定時消息
10.處理鼠標懸停
10.1向鼠標懸停的控件發送鼠標懸停消息
10.2如果當前控件有提示消息,創建消息提示窗體
11.處理鼠標離開事件,關閉消息提示框,發送鼠標離開消息,取消鼠標的追蹤
12.鼠標移動時,開始追蹤鼠標
12.1處理鼠標移動時,鼠標在控件上進入,移動,懸停和離開的消息
13.處理鼠標左鍵按下的消息設定活動的焦點的控件
14.鼠標雙擊事件處理,向需要接收鼠標雙擊事件的控件發送雙擊事件
15.鼠標左鍵抬起時,向上次接收到點擊消息的控件發送鼠標左鍵抬起的消息
16.鼠標右鍵按下時,向需要接收鼠標右鍵按下的控件發送右鍵按下消息
17.鼠標右鍵快捷菜單消息,將該消息通知給上次點擊過的按鈕
18.滾輪消息時,象鼠標所在的控件發送滾輪消息
19.WM_CHAR 消息時,向獲得焦點的控件發送該消息
20.鍵盤按下時,向焦點控件發送該鍵盤消息,並設定焦點控件為鍵盤消息控件
21.鍵盤按鍵抬起時,向事鍵盤消息控件發送該事件
22.設定鼠標光標消息時,獲得光標所在控件接收該消息
23.通知消息到來時,加OCM_BASE后發送通知消息
24.命令消息到來,加OCM_BASE后發送消息
25.WM_CTLCOLOREDIT,STATIC消息到來后,加OCM_BASE后發送消息
+---bool MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes);
——colin3dmax 分析於2011-6-15 22:00
在此我再次感謝colin3dmax的無私分享還有為duilib開源做出貢獻的人哈