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: 在最下层具有容器特性的控件(CWindowCanvasUI控件)上画容器内所有控件(控件实例对象保存在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: 在最下层具有容器特性的控件(CWindowCanvasUI控件)容器内查找相应控件对象
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

  

DirectUI的初步分析(二)

这篇文章是<DirectUI的初步分析>后的延续,在本文中主要是针对整体的框架结合MVC模式来进行分析,不会涉及具体的代码。
  
(1)Subject(目标)
I)目标知道它的观察者。可以有任意多个观察者观察同一个目标。
II)提供注册和删除观察者对象的接口。
目标应该就是CControlUI类,关于第一点观察者观察的是CControlUI,当多个观察者观察的同一个目标状态发生改变时也就是多视图更新;关于第二点CControlUI中并没有定义这样的接口,这个工作是由CPaintManagerUI来完成的,不过没有再另行定义虚接口类。CPaintManagerUI的功能不仅限于此,还完成了更多的工作,会在下面做详细描述。
(2)Observer(观察者)
为那些在目标发生改变时需获得通知的(观察者)对象定义一个更新接口。
INotifyUI虚接口类的Notify函数。关于这一点单纯的观察者模式是有缺点的,如果存在多个观察者对象那就要为每一个观察者对象定义一个同名方法(即虚函数Notify)这加大了开销。如果用委托那观察者对象的方法就可以不同名(将观察者对象的方法委托给目标)
(3)ConcreteSubject(具体目标)
I)将有关状态存入各ConcreteObserver对象。
II)当它的状态发生改变时,向它的各个观察者发出通知。
应该就是继承自CControlUI或CContainUI等的各种控件类,当有事件触发时会通知观察者对象。关于第一点如进度条拖动时通知观察者对象获取值;关于第二点如按钮按下通知观察者
(4)ConcreteObserver(具体观察者)
I)维护一个指向ConcreteSubject对象的引用
II)存储有关状态,这些状态应与目标的状态保持一致
III)实现Observer的更新接口以使自身状态与目标的状态保持一致
派生自INotifyUI的类如CStandardPageWnd,它实现了Notify虚函数、根据名称或ID获得控件实例对象指针、根据控件通知保存值或控件状态等等。
(5)众所周知MVC方式是从观察者模式演变而来。从第(4)描述来看CStandardPageWnd做为观察者并没有更新视图,原因何在?视图更新的工作实际上由CPaintManagerUI来承担了,这样做的好处就是当目标状态或数据发生改变时视图能立即更新反映变化,观察者收到通知后只需关注状态存储或数据处理,这也是文档视图的分离。
(6)我们知道WINDOW操作系统是基于窗口和消息的系统,所以目标状态的改变也是基于窗口消息触发而改变。CStandardPageWnd的父类CWindowWnd完成了这一部分同平台紧密相关的工作,而CPaintManagerUI完成了消息处理及改变目标状态的工作,理论上来说如果把这两部分加上相对独立的渲染部分替换就可以实现跨平台了。是否可以认为这些是控制器完成的工作?

DirectUI的初步分析(三)

基于(http://directui.googlecode.com/)最新版r62进行分析,对于未使用的控件属性未做分析
  
属性
一、主窗口属性(XML中标签'Window')
size   窗口的大小
sizebox  
caption   标题栏的宽度高度
roundcorner  窗口的圆角矩形的半径
mininfo
showdirty  是否用矩形框标示需要重画的区域
  
二、公共属性('Window'标签和第一个容器标签间的内容)
Image   图片的来源以及图片文件的名称,一般是用于html方式文字的标签{i}
Font   字体配置方案,对应CLabelUI的font属性
Default   指定Button、VScrollBar、HScrollBar的几种状态图片属性
  
三、控件(容器)属性
CControlUI
1    float  和pos组合使用,根据所处容器窗口坐标计算其窗口坐标。如果不指定此属性则背景图片会拉伸到整个容器,文字会水平居左垂直居中显示
2    pos  同上
3    padding  控件文字显示位置缩进距离
4    bkcolor  第一种背景颜色,如果指定第二种背景颜色则背景为垂直方向的渐变色
5    bkcolor2  第二种背景颜色
6    bordercolor 边框线颜色
7    bordersize  边框线尺寸
8    bkimage  背景图片
9    width 
10    height
11    minwidth
12    minheight
13    maxwidth
14    maxheight
15    name  控件标识,在同一窗口内具有唯一性
16    text  显示文字
17    tooltip  tip信息
18    userdata  扩展用户数据
19    enabled  是否激活
20    mouse  是否响应鼠标消息,如果为false则由其最近的左兄弟或父亲结点处理
21    visible  是否可见
22    shortcut
23    relativepos 子控件(容器)相对于父控件(容器)的客户区坐标
  
CContainerUI -> CControlUI
1    inset  容器内的控件的可显示区域要上下左右各缩进多少;如果容器嵌套容器则用于指定子容器相对父容器的偏移
2    mousechild
3    vscrollbar  垂直滚动条的几种状态图片属性
4    hscrollbar  水平滚动条的几种状态图片属性
5    childpadding
  
CHorizontalLayoutUI -> CContainerUI
1    sepwidth
2    sepimm
  
CTileLayoutUI -> CContainerUI
1    columns  容器内控件按几列显示,会自动根据列数计算行数
     
CLabelUI -> CControlUI
1    align  文字对齐方式
2    font  文字字体属性
3    textcolor  文字颜色
4    disabledtextcolor 非激活状态下文字颜色
5    textpadding
6    showhtml  html方式显示文字,可参考DrawHtmlText函数说明
7    fitallArea  状态图片是否需要填充整个区域,false可以用来画checkbox & radio box
8    tipimage  tip的背景图片
  
CButtonUI -> CLabelUI -> CControlUI
1    normalimage 正常状态图片
2    hotimage  高亮状态图片
3    pushedimage 按下状态图片
4    focusedimage 获得焦点状态图片
5    disabledimage 非激活状态图片
6    disabled
  
COptionUI -> CButtonUI -> CLabelUI -> CControlUI
1    group  true则表示是多个option组合使用,且所有option必须包含在容器内。
2    selected  初始状态为选中,如果指定了group属性则当前选中项只有一个,而且属性字符中group要位于selected前面。
3    selectedimage 选中状态图片
4    foreimage  checkbox或radio box选中时前景小图片
5    selectedtextcolor 文字颜色
  
CTextUI -> CLabelUI -> CControlUI
  
CProgressUI -> CLabelUI -> CControlUI
1    fgimage  前景进度条图片,一般是根据百分比做拉伸处理
2    hor  为true则水平显示
3    min  最小值
4    max  最大值
5    value  当前值
  
CSliderUI -> CProgressUI -> CLabelUI -> CControlUI
1    thumbimage  滑标正常状态图片
2    thumbhotimage 滑标高亮状态图片
3    thumbpushedimage 滑标按下状态图片
4    thumbsize  滑标大小
注:如果需要实现带轨道的滑动条控制,则需要指定父类CControlUI的bkimage属性;如果要实现计数,则需要指定父类CProgressUI的min/max/value属性
  
CEditUI -> CLabelUI
1    readonly  只读属性
2    password  密文"*"显示方式
3    normalimage 正常状态图片
4    hotimage  高亮状态图片
5    focusedimage 获得焦点状态图片
6    disabledimage 非激活状态图片
7    multiline  多行属性
8    maxchar  是大可输入字符数
     
CComboUI -> CContainerUI -> CControlUI
1    textpadding
2    normalimage
3    hotimage
4    pushedimage
5    focusedimage
6    disabledimage
7    itemfont
8    itemalign
9    itemtextpadding
10    itemtextcolor
11    itembkcolor
12    itemimage
13    itemselectedtextcolor
14    itemselectedbkcolor
15    itemselectedimage
16    itemhottextcolor
17    itemhotbkcolor
18    itemhotimage
19    itemdisabledtextcolor
20    itemdisabledbkcolor
21    itemdisabledimage
22    itemlinecolor
23    itemshowhtml
  
CScrollbarUI -> CControlUI
1    button1normalimage
2    button1hotimage
3    button1pushedimage
4    button1disabledimage
5    button2normalimage
6    button2hotimage
7    button2pushedimage
8    button2disabledimage
9    thumbnormalimage
10    thumbhotimage
11    thumbpushedimage
12    thumbdisabledimage
13    railnormalimage
14    railhotimage
15    railpushedimage
16    raildisabledimage
17    bknormalimage
18    bkhotimage
19    bkpushedimage
20    bkdisabledimage
21    hor
22    linesize
23    range
24    value
  
CListUI -> CVerticalLayoutUI -> CContainerUI
1    header
2    headerbkimage
3    expanding
4    multiexpanding
5    itemfont
6    itemalign
7    itemtextpadding
8    itemtextcolor
9    itembkcolor
10    itemimage
11    itemselectedtextcolor
12    itemselectedbkcolor
13    itemselectedimage
14    itemhottextcolor
15    itemhotbkcolor
16    itemhotimage
17    itemdisabledtextcolor
18    itemdisabledbkcolor
19    itemdisabledimage
20    itemlinecolor
21    itemshowhtml
  
CListHeaderItemUI -> CControlUI
1    dragable
2    sepwidth
3    align
4    font
5    textcolor
6    showhtml
7    normalimage
8    hotimage
9    pushedimage
10    focusedimage
11    sepimage
  
CListElementUI -> CControlUI
1    selected
  
CListExpandElementUI -> CListTextElementUI -> CListLabelElementUI -> CListElementUI -> CControlUI
1    expander
2    hideself
  
CListContainerElementUI -> CContainerUI
1    selected
05-11 13:12