最近由于項(xiàng)目的需要學(xué)習(xí)了一下DirectUI方面的東西,主要借鑒的是一個(gè)國(guó)外程序員寫(xiě)的代碼(見(jiàn)引用一),看了后發(fā)現(xiàn)它更多的是探討一種實(shí)現(xiàn)的可能性和思路,和實(shí)際應(yīng)用還是有距離的,不過(guò)其實(shí)現(xiàn)還是很有意思的。在寫(xiě)此小結(jié)的時(shí)候又發(fā)現(xiàn)國(guó)內(nèi)一個(gè)程序員將這個(gè)代碼部分移植到WINCE下的代碼(見(jiàn)引用二),因?yàn)槠脚_(tái)的差異性要完全開(kāi)發(fā)一個(gè)WINCE下的實(shí)際代碼還是需要時(shí)間的。
由于本人GUI開(kāi)發(fā)做得少,工作中有關(guān)這方面的東西主要是提供思路和方法,學(xué)習(xí)DirectUI的主要目的是為了更新知識(shí)學(xué)習(xí)思路,文章中難免出現(xiàn)錯(cuò)誤。
一、核心
1 、CWindowWnd: 窗口對(duì)象類(lèi)(窗口實(shí)例對(duì)象父類(lèi))
2 、CDialogBuilder: 創(chuàng)建控件類(lèi),分析腳本并用遞歸方式(_Parse函數(shù))創(chuàng)建所有控件實(shí)例
3 、CPaintManagerUI: 窗口消息及圖形繪制管理器類(lèi)
4 、CGUIRenderEngineUI: 圖形渲染引擎類(lèi),在離屏DC中生成最終顯示的圖形,可根據(jù)需要擴(kuò)展多種圖形效果顯示。
5 、INotifyUI: 事件通知抽象類(lèi)
6 、IMessageFilterUI: 消息過(guò)濾抽象類(lèi)
二、控件
CControlUI: 控件管理抽象父類(lèi),父類(lèi)INotifyUI
1 、button
CButtonUI: 按鈕控件
COptionUI: 選擇按鈕控件
2 、combox
CSingleLinePickUI:
CDropDownUI: 下拉控件,父類(lèi)另有CContainerUI和IListOwnerUI
3 、decoration
CTitleShadowUI: 陰影效果
CListHeaderShadowUI
CSeparatorLineUI
CFadedLineUI
4 、edit
CSingleLineEditUI: 單行編輯框控件
CMultiLineEditUI: 多行編輯框控件
5 、label
CLabelPanelUI: 可設(shè)置背景色和文字色的靜態(tài)標(biāo)簽控件
CGreyTextHeaderUI
6 、list
第一種:
CListUI: 列表控件,包含以下幾個(gè)子控件
( 1 )CListHeaderItemUI: 列表頭
( 2 )CListExpandElementUI: 列表項(xiàng)
第二種:用法不明
CListHeaderUI: 列表頭
CListElementUI: 列表項(xiàng),父類(lèi)另有IListItemUI
CListLabelElementUI: 列表項(xiàng),父類(lèi)CListElementUI
CListTextElementUI: 列表項(xiàng)
CListFooterUI: 列表尾
7 、panel
CTextPanelUI: 父類(lèi)CLabelPanelUI
CTaskPanelUI:
CNavigatorPanelUI: 導(dǎo)航面板,父類(lèi)另有IListOwnerUI,包含CNavigatorButtonUI子控件
CSearchTitlePanelUI:
CImagePanelUI: 圖片顯示
CWarningPanelUI: 警告提示,父類(lèi)CTextPanelUI
CPaddingPanelUI: 填充欄
8 、tab
CTabFolderUI: 父類(lèi)另有CContainerUI和IListOwnerUI
CTabPageUI: 父類(lèi)另有CContainerUI
9 、toolbar
CToolbarUI: 工具欄,包含以下幾個(gè)子控件
( 1 )CToolButtonUI: 圖形按鈕
( 2 )CToolSeparatorUI: 分隔符
( 3 )CToolGripperUI: gripper
10 、title
CToolbarTitlePanelUI:
11 、statusbar
CStatusbarUI: 狀態(tài)欄,父類(lèi)另有CContainerUI
12 、anim
CAnimJobUI: 動(dòng)畫(huà)顯示類(lèi)
13 、ActiveX
CActiveXUI:
三、容器:
CContainerUI: 容器類(lèi),父類(lèi)CControlUI和IContainerUI。可以認(rèn)為容器是特殊的控件(見(jiàn)上面控件類(lèi)關(guān)于父類(lèi)的說(shuō)明),其目的之一是具有容器特性的控件可以容納其它控件,這樣可以方便的實(shí)現(xiàn)控件的疊加;目的之二實(shí)際的窗口只有一個(gè),對(duì)于疊加的控件必須要進(jìn)行層次管理才能正確繪圖和事件分發(fā)。另外可參見(jiàn)引用三
1 、畫(huà)布: CCanvasUI(父類(lèi)CContainerUI),可繪制背景色、畫(huà)線、貼圖
CWindowCanvasUI: 父類(lèi)CCanvasUI
CControlCanvasUI: 父類(lèi)CCanvasUI
CWhiteCanvasUI: 父類(lèi)CCanvasUI
CDialogCanvasUI: 父類(lèi)CCanvasUI
CTabFolderCanvasUI: 父類(lèi)CCanvasUI
2 、布局: 管理不同層次的控件
CDialogLayoutUI: 父類(lèi)CContainerUI
CVerticalLayoutUI: 父類(lèi)CContainerUI
CHorizontalLayoutUI: 父類(lèi)CContainerUI
CTileLayoutUI: 父類(lèi)CContainerUI
四、通用
1 、script
CMarkup
CMarkupNode
2 、language
CUIUtility
3 、multi - thread
CriticalSection
AutoCriticalSection
CMutex
CAutoMutex
CEvent
CAutoEvent
CManualEvent
五、主要數(shù)據(jù)成員
1 、CPaintManagerUI
CControlUI * m_pRoot: 如果控件是疊加的則存放最下層的控件對(duì)象,否則存放第一個(gè)創(chuàng)建的控件對(duì)象
CControlUI * m_pFocus: 存放獲得焦點(diǎn)的控件對(duì)象指針
CControlUI * m_pEventHover: 存放當(dāng)前有鼠標(biāo)移進(jìn)移出事件的控件對(duì)象指針
CControlUI * m_pEventClick: 存放當(dāng)前有點(diǎn)擊事件的控件對(duì)象指針
CControlUI * m_pEventKey: 存放當(dāng)前有按鍵事件的控件對(duì)象指針
CStdPtrArray m_aNotifiers: 記錄所有需要事件通知的窗口,根據(jù)窗口名稱(chēng)調(diào)用相應(yīng)的消息處理函數(shù)
CStdPtrArray m_aNameHash: 保存控件對(duì)象指針hash表(用控件名稱(chēng)生成hash值)
CStdPtrArray m_aPostPaint: panel的fade效果
CStdPtrArray m_aMessageFilters: 保存需要進(jìn)行消息過(guò)濾的控件或功能(如動(dòng)畫(huà)類(lèi))
CStdPtrArray m_aDelayedCleanup:
CStdPtrArray m_aPreMessages: 預(yù)處理消息
HWND m_hWndPaint: 控件布局窗口句柄
HDC m_hDcPaint: 控件布局窗口設(shè)備DC
HDC m_hDcOffscreen: 離屏內(nèi)存DC
HBITMAP m_hbmpOffscreen: 離屏內(nèi)存DC相關(guān)聯(lián)HBITMAP
2 、CControlUI
CPaintManagerUI * m_pManager: 窗口或控件繪圖及消息管理器
CControlUI * m_pParent: 邏輯上的父窗口(控件)對(duì)象指針
CStdString m_sName: 控件標(biāo)識(shí)
CStdString m_sText: 控件顯示標(biāo)題或顯示腳本字符串
CStdString m_sToolTip: 控制的Tip信息
3 、CContainerUI
CStdPtrArray m_items: 同一層的控件對(duì)象或控件對(duì)象的子對(duì)象,例如canvas上放置的按鈕、combox由edit和list兩個(gè)子對(duì)象組成,其它還有tab等。具體見(jiàn)CDropDownUI、CTabFolderUI、CNavigatorPanelUI三個(gè)類(lèi)定義
4 、CDialogLayoutUI
CStdValArray m_aModes: 用于存放在Layout上絕對(duì)坐標(biāo)轉(zhuǎn)成相對(duì)坐標(biāo)(CDialogLayoutUI::RecalcArea)的控件對(duì)象(指針、大小、模式),目的是否為了讓布局上的控件隨布局變化而變化,能夠正確繪圖???
六、控件屬性
待完成
七、腳本例子
< 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是布局窗口對(duì)象指針,并與布局窗口綁定(SetWindowLongPtr)
STEP03. m_pm.MessageHandler: m_pm為CPaintManagerUI唯一實(shí)例對(duì)象
STEP04. CPaintManagerUI::MessageHandler: 處理WM_PAINT
STEP05. m_pRoot -> DoPaint: m_pRoot為最下層的控件對(duì)象,在本例中為CWindowCanvasUI控件(對(duì)應(yīng)腳本中的WindowCanvas)
STEP06. CCanvasUI::DoPaint: 往畫(huà)布上繪制背景色、邊角弧形、水印等。
STEP07. CContainerUI::DoPaint: 在布局窗口(對(duì)應(yīng)腳本中DialogLayout)畫(huà)所有控件(控件實(shí)例對(duì)象保存在m_items中)
STEP08. pControl -> DoPaint: pControl為控件對(duì)象實(shí)例之一,利用多態(tài)性來(lái)調(diào)用不同控件的繪圖方法
STEP09. CButtonUI::DoPaint: 按鈕(對(duì)應(yīng)腳本中Button)繪圖方法,有下面兩種方法
i)文字方法: CGUIRenderEngineUI::DPaintButton
ii)圖片方法: CGUIRenderEngineUI::DoPaintBitmap
STEP10. 新一輪消息循環(huán)
2 、事件
STEP01. CWindowWnd::__WndProc:
STEP02. pThis -> HandleMessage:
STEP03. m_pm.MessageHandler:
STEP04. CPaintManagerUI::MessageHandler: 處理WM_LBUTTONDOWN
STEP05. CPaintManagerUI::FindControl: 根據(jù)鼠標(biāo)坐標(biāo)查找相應(yīng)控件對(duì)象
STEP06. m_pRoot -> FindControl:
STEP07. CContainerUI::FindControl: 在布局窗口上查找相應(yīng)控件對(duì)象
STEP08. CControlUI::FindControl: 在m_items中查找相對(duì)應(yīng)的控件對(duì)象
STEP09. pControl -> Event: pControl為控件對(duì)象實(shí)例之一,利用多態(tài)性來(lái)調(diào)用不同控件的事件方法
STEP10. CPaintManagerUI::MessageHandler: 處理WM_LBUTTONUP
STEP11. m_pEventClick -> Event: 利用多態(tài)性來(lái)調(diào)用不同控件的事件方法(m_pEventClick說(shuō)明見(jiàn) " 主要數(shù)據(jù)成員 " )
STEP12. CButtonUI::Event: 按鈕(對(duì)應(yīng)腳本中Button)事件方法
STEP13. CButtonUI::Activate:
STEP14. m_pManager -> SendNotify: 傳遞控件對(duì)象指針和觸發(fā)事件(文本方式)
STEP15. CPaintManagerUI::SendNotify: 注意以下兩點(diǎn)實(shí)現(xiàn)是完成控制和業(yè)務(wù)分離的關(guān)鍵
i)利用重載特性調(diào)用注冊(cè)的監(jiān)聽(tīng)對(duì)象(窗口)的消息處理函數(shù)Notify(監(jiān)聽(tīng)對(duì)象保存在m_aNotifiers中)
for ( int i = 0 ; i < m_aNotifiers.GetSize(); ++ i )

{
static_cast < INotifyUI *> (m_aNotifiers[i]) -> Notify(Msg);
}
ii)布局窗口CStartPageWnd的消息處理,宏定義展開(kāi)后實(shí)際就是重載的Notify函數(shù)
DIRECT_BEGIN_NOTIFYMAP(CStartPageWnd)
PROCESS_BUTTON_CLICK(_T( " ok " ),OnOk)
。。。
DIRECT_END_NOTIFYMAP(CStandardPageWnd)
STEP16. CStartPageWnd::OnOk: 控件消息處理函數(shù),此處可以加入具體的事務(wù)邏輯處理
STEP17. 新一輪消息循環(huán)
3 、消息定義(文本)
" click " 、 " changed " 、 " link " 、 " browse " 、 " itemclick " 、 " itemselect " 、 " dropdown " 、 " itemactivate " 、 " headerdragging " 、 " headerclick " 、 " headerdragged " 、 " itemexpand " 、 " itemcollapse " 、 " windowinit " 、 " killfocus " 、 " setfocus " 、 " timer "
九、疑問(wèn)
1 、Edit、Combox的下拉列表部分、ScrollBar、Tooltip控件是創(chuàng)建的實(shí)際窗口,這個(gè)與DirectUI思路還是有差別的
2 、實(shí)例中有創(chuàng)建一個(gè)不進(jìn)行消息處理的窗口(CFrameWindowWnd),然后又創(chuàng)建了一個(gè)窗口(CStandardPageWnd)用于具體的控件布局。但是我用一個(gè)窗口也能實(shí)現(xiàn),原作者為什么這樣還不清楚
3 、控件是用文本形式來(lái)做標(biāo)識(shí)的,消息類(lèi)型是文本形式,是否改成數(shù)值型比較好
十、引用
引用一: 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的代碼很好,這個(gè)可以被運(yùn)用到商業(yè)上。
個(gè)人覺(jué)得這個(gè)框架比mfc甚至wtl的在構(gòu)架、思想上高N倍。
首先 viksoe采用layout機(jī)制動(dòng)態(tài)計(jì)算各子窗口的坐標(biāo)位置,自適應(yīng)屏幕大小的變化。而MFC要求子窗口的坐標(biāo)位置硬編碼,結(jié)果要適應(yīng)不同分辨率的屏幕 非常困難。GTK + 在窗口布局時(shí)分為兩個(gè)階段,第一個(gè)階段父窗口先詢(xún)問(wèn)子窗口的最佳大小,第二個(gè)階段父窗口根據(jù)自己的大小計(jì)算子窗口的實(shí)際大小,子窗口根 據(jù)實(shí)際大小進(jìn)行調(diào)整。
其次viksoe采用容器機(jī)制來(lái)合理分離控件的職責(zé),MFC沒(méi)有容器這個(gè)概念,很難實(shí)現(xiàn)遞歸組合。viksoe中差 不多所有控件都是容器,都可以容納其它任何控件,而MFC只有頂層窗口才是容器,可以容納其它子控件。容器這個(gè)概念對(duì)代碼重用的影響非常之大,這里舉兩個(gè) 例子:其一是帶圖片的按鈕(BitmapButton),在viksoe中它就是CCanvasUI類(lèi)和CButtonUI的組合,而在MFC中,圖片和 文字都要自己繪制。前者的CCanvasUI類(lèi)和CButtonUI可以在很多地方重用,而后都的繪制代碼和事件處理代碼只有自己才能使用。在MFC中, 即使只是實(shí)現(xiàn)一個(gè)不同外觀的列表框,你都要采用自繪的方式,代碼重用非常困難,向列表框中加入其它控件就更麻煩了,要使用一些非同尋常的手段不可。
另 外說(shuō)句在驅(qū)動(dòng)里畫(huà)gui,這個(gè)和普通gui有所不同,上面說(shuō)的directUI還是用到了Windows的消息,而驅(qū)動(dòng)里只能自己hook key 、mouse 中斷。然后實(shí)現(xiàn)各種消息的派發(fā)。但這樣對(duì)兼容usb接口的鍵盤(pán)很成問(wèn)題。這實(shí)際相當(dāng)于自己實(shí)現(xiàn)了win32k里面的內(nèi)容。而驅(qū)動(dòng)里面畫(huà)圖其實(shí)不過(guò)是自己寫(xiě) 顯存。但又有很多兼容問(wèn)題要解決,別的不說(shuō),每種顯卡的顯存位置就要自己實(shí)現(xiàn),所以softICE直接做不下去了,syser在部分機(jī)器上也得靠 directX來(lái)獲取顯存。
我的blog hi.baidu.com / weolar
HTMLayoutSDK 有時(shí)間看下這個(gè),比較好用,用spy ++ 去抓,也抓不到任何窗口,而且簡(jiǎn)單.htm文件描述,做界面那叫一個(gè)方便,效果也很不錯(cuò),關(guān)鍵是免費(fèi),現(xiàn)在我都轉(zhuǎn)這個(gè)做界面了.
我現(xiàn)在正在研究viksoe的這個(gè)DirectUI庫(kù),把它改寫(xiě)成wchar_t的了,并把類(lèi)庫(kù)中使用的CWindowWnd換成了atl / wtl的 CWindowImpl, 我準(zhǔn)備好好的在這個(gè)DirectUI庫(kù)的基礎(chǔ)上把這個(gè)庫(kù)進(jìn)行進(jìn)一步的開(kāi)發(fā),做一個(gè)好用的強(qiáng)大的DirectUI庫(kù),有興趣一塊開(kāi)發(fā)的可以聯(lián)系我,放到 Google code上,大家一塊做 !
davidxifeng@gmail.com
csdn上留言也行.不過(guò)不會(huì)經(jīng)常查看