DirectUI的初步分析

最近由於項目的需要學習了一下DirectUI方面的東西,主要借鑑的是一個國外程序員寫的代碼(見引用一),看了後發現它更多的是探討一種實現的可能性和思路,和實際應用還是有距離的,不過其實現還是很有意思的。在寫此小結的時候又發現國內一個程序員將這個代碼部分移植到WINCE下的代碼(見引用二),因爲平臺的差異性要完全開發一個WINCE下的實際代碼還是需要時間的。
由於本人GUI開發做得少,工作中有關這方面的東西主要是提供思路和方法,學習DirectUI的主要目的是爲了更新知識學習思路,文章中難免出現錯誤。

一、核心
 1 、CWindowWnd: 窗口對象類(窗口實例對象父類)
 2 、CDialogBuilder: 創建控件類,分析腳本並用遞歸方式(_Parse函數)創建所有控件實例
 3 、CPaintManagerUI: 窗口消息及圖形繪製管理器類
 4 、CGUIRenderEngineUI: 圖形渲染引擎類,在離屏DC中生成最終顯示的圖形,可根據需要擴展多種圖形效果顯示。
 5 、INotifyUI: 事件通知抽象類
 6 、IMessageFilterUI: 消息過濾抽象類

二、控件
CControlUI: 控件管理抽象父類,父類INotifyUI
 1 、button
CButtonUI: 按鈕控件
COptionUI: 選擇按鈕控件

 2 、combox
CSingleLinePickUI:
CDropDownUI: 下拉控件,父類另有CContainerUI和IListOwnerUI

 3 、decoration
CTitleShadowUI: 陰影效果
CListHeaderShadowUI
CSeparatorLineUI
CFadedLineUI

 4 、edit
CSingleLineEditUI: 單行編輯框控件
CMultiLineEditUI: 多行編輯框控件

 5 、label
CLabelPanelUI: 可設置背景色和文字色的靜態標籤控件
CGreyTextHeaderUI

 6 、list
第一種:
CListUI: 列表控件,包含以下幾個子控件
( 1 )CListHeaderItemUI: 列表頭
( 2 )CListExpandElementUI: 列表項
第二種:用法不明
CListHeaderUI: 列表頭
CListElementUI: 列表項,父類另有IListItemUI
CListLabelElementUI: 列表項,父類CListElementUI
CListTextElementUI: 列表項
CListFooterUI: 列表尾

 7 、panel
CTextPanelUI: 父類CLabelPanelUI
CTaskPanelUI:
CNavigatorPanelUI: 導航面板,父類另有IListOwnerUI,包含CNavigatorButtonUI子控件
CSearchTitlePanelUI:
CImagePanelUI: 圖片顯示
CWarningPanelUI: 警告提示,父類CTextPanelUI
CPaddingPanelUI: 填充欄

 8 、tab
CTabFolderUI: 父類另有CContainerUI和IListOwnerUI
CTabPageUI: 父類另有CContainerUI

 9 、toolbar
CToolbarUI: 工具欄,包含以下幾個子控件
( 1 )CToolButtonUI: 圖形按鈕
( 2 )CToolSeparatorUI: 分隔符
( 3 )CToolGripperUI:  gripper

 10 、title
CToolbarTitlePanelUI:

 11 、statusbar
CStatusbarUI: 狀態欄,父類另有CContainerUI

 12 、anim
CAnimJobUI: 動畫顯示類

 13 、ActiveX
CActiveXUI:

三、容器:
CContainerUI: 容器類,父類CControlUI和IContainerUI。可以認爲容器是特殊的控件(見上面控件類關於父類的說明),其目的之一是具有容器特性的控件可以容納其它控件,這樣可以方便的實現控件的疊加;目的之二實際的窗口只有一個,對於疊加的控件必須要進行層次管理才能正確繪圖和事件分發。另外可參見引用三
 1 、畫布: CCanvasUI(父類CContainerUI),可繪製背景色、畫線、貼圖
CWindowCanvasUI: 父類CCanvasUI
CControlCanvasUI: 父類CCanvasUI
CWhiteCanvasUI: 父類CCanvasUI
CDialogCanvasUI: 父類CCanvasUI
CTabFolderCanvasUI: 父類CCanvasUI
 2 、佈局: 管理不同層次的控件
CDialogLayoutUI: 父類CContainerUI
CVerticalLayoutUI: 父類CContainerUI
CHorizontalLayoutUI: 父類CContainerUI
CTileLayoutUI: 父類CContainerUI

四、通用
 1 、script
CMarkup
CMarkupNode

 2 、language
CUIUtility

 3 、multi - thread
CriticalSection
AutoCriticalSection
CMutex
CAutoMutex
CEvent
CAutoEvent
CManualEvent

五、主要數據成員
 1 、CPaintManagerUI
CControlUI *  m_pRoot: 如果控件是疊加的則存放最下層的控件對象,否則存放第一個創建的控件對象
CControlUI *  m_pFocus: 存放獲得焦點的控件對象指針
CControlUI *  m_pEventHover: 存放當前有鼠標移進移出事件的控件對象指針
CControlUI *  m_pEventClick: 存放當前有點擊事件的控件對象指針
CControlUI *  m_pEventKey: 存放當前有按鍵事件的控件對象指針
CStdPtrArray m_aNotifiers: 記錄所有需要事件通知的窗口,根據窗口名稱調用相應的消息處理函數
CStdPtrArray m_aNameHash: 保存控件對象指針hash表(用控件名稱生成hash值)
CStdPtrArray m_aPostPaint: panel的fade效果
CStdPtrArray m_aMessageFilters: 保存需要進行消息過濾的控件或功能(如動畫類)
CStdPtrArray m_aDelayedCleanup:
CStdPtrArray m_aPreMessages: 預處理消息
HWND m_hWndPaint: 控件佈局窗口句柄
HDC m_hDcPaint: 控件佈局窗口設備DC
HDC m_hDcOffscreen: 離屏內存DC
HBITMAP m_hbmpOffscreen: 離屏內存DC相關聯HBITMAP

 2 、CControlUI
CPaintManagerUI *  m_pManager: 窗口或控件繪圖及消息管理器
CControlUI *  m_pParent: 邏輯上的父窗口(控件)對象指針
CStdString m_sName: 控件標識
CStdString m_sText: 控件顯示標題或顯示腳本字符串
CStdString m_sToolTip: 控制的Tip信息

 3 、CContainerUI
CStdPtrArray m_items: 同一層的控件對象或控件對象的子對象,例如canvas上放置的按鈕、combox由edit和list兩個子對象組成,其它還有tab等。具體見CDropDownUI、CTabFolderUI、CNavigatorPanelUI三個類定義

 4 、CDialogLayoutUI
CStdValArray m_aModes: 用於存放在Layout上絕對座標轉成相對座標(CDialogLayoutUI::RecalcArea)的控件對象(指針、大小、模式),目的是否爲了讓佈局上的控件隨佈局變化而變化,能夠正確繪圖???

六、控件屬性
待完成

七、腳本例子
 < Dialog >
   < WindowCanvas pos = / " 0,0,600,800/ " >
   < DialogLayout pos = / " 0,0,600,800/ " >
     < Button pos = / " 390, 30, 490, 58/ "  text = / " OK/ "  name = / " ok/ " />
   </ DialogLayout >
   </ WindowCanvas >
 </ Dialog >
 
八、繪圖及事件處理
 1 、繪圖
STEP01. CWindowWnd::__WndProc: 主窗口程序
STEP02. pThis -> HandleMessage: pThis是佈局窗口對象指針,並與佈局窗口綁定(SetWindowLongPtr)
STEP03. m_pm.MessageHandler: m_pm爲CPaintManagerUI唯一實例對象
STEP04. CPaintManagerUI::MessageHandler: 處理WM_PAINT
STEP05. m_pRoot -> DoPaint: m_pRoot爲最下層的控件對象,在本例中爲CWindowCanvasUI控件(對應腳本中的WindowCanvas)
STEP06. CCanvasUI::DoPaint: 往畫布上繪製背景色、邊角弧形、水印等。
STEP07. CContainerUI::DoPaint: 在佈局窗口(對應腳本中DialogLayout)畫所有控件(控件實例對象保存在m_items中)
STEP08. pControl -> DoPaint: pControl爲控件對象實例之一,利用多態性來調用不同控件的繪圖方法
STEP09. CButtonUI::DoPaint: 按鈕(對應腳本中Button)繪圖方法,有下面兩種方法
i)文字方法: CGUIRenderEngineUI::DPaintButton
ii)圖片方法: CGUIRenderEngineUI::DoPaintBitmap
STEP10. 新一輪消息循環

 2 、事件
STEP01. CWindowWnd::__WndProc:
STEP02. pThis -> HandleMessage:
STEP03. m_pm.MessageHandler:
STEP04. CPaintManagerUI::MessageHandler: 處理WM_LBUTTONDOWN
STEP05. CPaintManagerUI::FindControl: 根據鼠標座標查找相應控件對象
STEP06. m_pRoot -> FindControl:
STEP07. CContainerUI::FindControl: 在佈局窗口上查找相應控件對象
STEP08. CControlUI::FindControl: 在m_items中查找相對應的控件對象
STEP09. pControl -> Event: pControl爲控件對象實例之一,利用多態性來調用不同控件的事件方法
STEP10. CPaintManagerUI::MessageHandler: 處理WM_LBUTTONUP
STEP11. m_pEventClick -> Event: 利用多態性來調用不同控件的事件方法(m_pEventClick說明見 " 主要數據成員 " )
STEP12. CButtonUI::Event: 按鈕(對應腳本中Button)事件方法
STEP13. CButtonUI::Activate:
STEP14. m_pManager -> SendNotify: 傳遞控件對象指針和觸發事件(文本方式)
STEP15. CPaintManagerUI::SendNotify: 注意以下兩點實現是完成控制和業務分離的關鍵
i)利用重載特性調用註冊的監聽對象(窗口)的消息處理函數Notify(監聽對象保存在m_aNotifiers中)
 for (  int  i  =   0 ; i  <  m_aNotifiers.GetSize();  ++ i )
  {
    static_cast < INotifyUI *> (m_aNotifiers[i]) -> Notify(Msg);
}
ii)佈局窗口CStartPageWnd的消息處理,宏定義展開後實際就是重載的Notify函數
DIRECT_BEGIN_NOTIFYMAP(CStartPageWnd)
    PROCESS_BUTTON_CLICK(_T( " ok " ),OnOk)
    。。。
DIRECT_END_NOTIFYMAP(CStandardPageWnd)
STEP16. CStartPageWnd::OnOk: 控件消息處理函數,此處可以加入具體的事務邏輯處理
STEP17. 新一輪消息循環

 3 、消息定義(文本)
 " click " 、 " changed " 、 " link " 、 " browse " 、 " itemclick " 、 " itemselect " 、 " dropdown " 、 " itemactivate " 、 " headerdragging " 、 " headerclick " 、 " headerdragged " 、 " itemexpand " 、 " itemcollapse " 、 " windowinit " 、 " killfocus " 、 " setfocus " 、 " timer "
 
九、疑問
 1 、Edit、Combox的下拉列表部分、ScrollBar、Tooltip控件是創建的實際窗口,這個與DirectUI思路還是有差別的
 2 、實例中有創建一個不進行消息處理的窗口(CFrameWindowWnd),然後又創建了一個窗口(CStandardPageWnd)用於具體的控件佈局。但是我用一個窗口也能實現,原作者爲什麼這樣還不清楚
 3 、控件是用文本形式來做標識的,消息類型是文本形式,是否改成數值型比較好

十、引用
引用一: http: // www.viksoe.dk/code/windowless1.htm
 引用二: http: // directui.googlecode.com/
 引用三: http: // www.cnblogs.com/cutepig/archive/2010/06/14/1758204.html
 
 handless UI (direct UI)
http: // www.viksoe.dk/code/windowless1.htm
 
viksoe的代碼很好,這個可以被運用到商業上。
個人覺得這個框架比mfc甚至wtl的在構架、思想上高N倍。
首先 viksoe採用layout機制動態計算各子窗口的座標位置,自適應屏幕大小的變化。而MFC要求子窗口的座標位置硬編碼,結果要適應不同分辨率的屏幕 非常困難。GTK + 在窗口布局時分爲兩個階段,第一個階段父窗口先詢問子窗口的最佳大小,第二個階段父窗口根據自己的大小計算子窗口的實際大小,子窗口根 據實際大小進行調整。

其次viksoe採用容器機制來合理分離控件的職責,MFC沒有容器這個概念,很難實現遞歸組合。viksoe中差 不多所有控件都是容器,都可以容納其它任何控件,而MFC只有頂層窗口才是容器,可以容納其它子控件。容器這個概念對代碼重用的影響非常之大,這裏舉兩個 例子:其一是帶圖片的按鈕(BitmapButton),在viksoe中它就是CCanvasUI類和CButtonUI的組合,而在MFC中,圖片和 文字都要自己繪製。前者的CCanvasUI類和CButtonUI可以在很多地方重用,而後都的繪製代碼和事件處理代碼只有自己才能使用。在MFC中, 即使只是實現一個不同外觀的列表框,你都要採用自繪的方式,代碼重用非常困難,向列表框中加入其它控件就更麻煩了,要使用一些非同尋常的手段不可。

另 外說句在驅動裏畫gui,這個和普通gui有所不同,上面說的directUI還是用到了Windows的消息,而驅動裏只能自己hook key 、mouse 中斷。然後實現各種消息的派發。但這樣對兼容usb接口的鍵盤很成問題。這實際相當於自己實現了win32k裏面的內容。而驅動裏面畫圖其實不過是自己寫 顯存。但又有很多兼容問題要解決,別的不說,每種顯卡的顯存位置就要自己實現,所以softICE直接做不下去了,syser在部分機器上也得靠 directX來獲取顯存。
我的blog hi.baidu.com / weolar

 

HTMLayoutSDK 有時間看下這個,比較好用,用spy ++ 去抓,也抓不到任何窗口,而且簡單.htm文件描述,做界面那叫一個方便,效果也很不錯,關鍵是免費,現在我都轉這個做界面了.

 
我現在正在研究viksoe的這個DirectUI庫,把它改寫成wchar_t的了,並把類庫中使用的CWindowWnd換成了atl / wtl的 CWindowImpl, 我準備好好的在這個DirectUI庫的基礎上把這個庫進行進一步的開發,做一個好用的強大的DirectUI庫,有興趣一塊開發的可以聯繫我,放到 Google code上,大家一塊做 !
 
[email protected]
csdn上留言也行.不過不會經常查看
 
 關注Game內嵌Web瀏覽器內核(HTML Rendering Engine)
  2008 - 10 - 13   21 : 51 
網絡遊戲在遊戲內部經常會有一些Web方面的顯示需求,利用HTML來實現UI這個早已不是新鮮的玩意,雲風就曾經提到大話西遊1中採用內嵌IE來實現客戶端的UI,儘管當時這種技術方案沒有成功,但是對於利用HTML Rendering這樣的解析渲染引擎來表現客戶端GUI的技術探索還在不斷的深入。
        HTML Rendering Engine一般由DOM構建,HTML / CSS解析,Layout Engine,屏幕渲染等幾大模塊構成。
        其中LayoutEngine負責獲取頁面的內容(HTML、XML、CSS、圖片),並按照W3c的標準規則計算網頁顯示方式,並最終輸出到屏幕。由於佈局引擎負責了最重要的功能,因此可以被看作是瀏覽器的內核。
        目前比較有名的內核如下:
        Gecko,以此爲內核的瀏覽器最出名的莫過於Firefox了。
        Webkit則由於google的Chrome而更加出名。Webkit是一個開源的HTML 渲染引擎,由蘋果公司基於 KDE 的 KHTML 項目開發而成。
        當然由於Window的一統天下,IE的內核Trident也被很多應用所採用,GoogleTalk就是採用Trident來渲染對話界面的。
        從這個Wiki上還能看到主流瀏覽器內核的比較情況:http: // en.wikipedia.org/wiki/Comparison_of_layout_engines
    
        對於OnlineGame的簡單Web應用需求,其實可以找一些輕量級的內核。HTMLayout就是這樣一款針對WebUI的桌面應用和方便嵌入而設計的。但是HTMLayout並非完整特性的Web瀏覽器,對於一些非標準的HTML標記的渲染還有些問題,不過對於一個輕量級的嵌入引擎來說已經足夠完美了。
        官網如下:http: // www.terrainformatica.com/htmlayout/
         其附帶的SDK中包含了一個利用DX來渲染表現的例子,原理很簡單就是利用RenderingEngine將HTML解析輸出到位圖上,並轉由DX的材質輸出。官網下載的例子採用DX8來寫的,需要做一些簡單改動就可以了。MSN的桌面寵物多貓就利用HTMLayout來實現GUI的。
   
        第二人生中內嵌的瀏覽器庫llMozLib,就是通過內嵌Gecko來進行HTML的渲染顯示的,可以在http: // ubrowser.com/找到詳細的介紹,也可以從第二人生的官網上找到源代碼。這個功能就強大多了,值得下功夫研究一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章