天天看點

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/找到詳細的介紹,也可以從第二人生的官網上找到源代碼。這個功能就強大多了,值得下功夫研究一下。 

繼續閱讀