打开DuiFarm项目DuiFarm.cpp文件。在总体资源解析、控件创建、控件加载与绘图。

My first Duilib program

  于《Duilib源码分析(一)整体框架》、《Duilib源码分析(二)控件构造器—CDialogBuilder》以及《Duilib源码分析(三)XML解析器—CMarkup》中我们曾经起简单的角度去分析框架操作流程与消息流程,只能针对其来核心的记忆,此处我们将经过实际的比方分析,duilib创建的工,在合资源解析、控件创建、控件加载与绘图,控件数据处理等管理的浑过程进行整并:

  1. Prepare for development

  为了有利于分析,我们仍由种类中附带的工程“TestApp1”进行重新尖锐之上,以下执行流程也切实的盖步骤及操作内容;

  打开DuiFarm项目DuiFarm.cpp文件,将除_tWinMain函数之外所有内容剔除。删除后底DuiFarm.cpp内容如下:

  从入口点WinMain:

int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{return 0;}

    1.
CPaintManagerUI整个绘制UI的管理器,调用静态成员函数设置当前应用程序实例句柄和资源路(主要也各种xml和图表资源);

  以DuiFarm.cpp文件首引起入头文件UIlib.h,并援引namespace,及有关预编译指令。如下:

    2. 初始化COM组件;

 1 #include "..\\..\\duilib-master\\DuiLib\\UIlib.h"
 2 using namespace DuiLib;
 3 #ifdef _DEBUG
 4     #ifdef _UNICODE
 5         #pragma comment(lib,"..\\..\\duilib-master\\Lib\\Duilib_ud.lib")
 6     #else
 7         #pragma comment(lib,"..\\..\\duilib-master\\Lib\\Duilib_d.lib")
 8     #endif
 9 #else
10     #ifdef _UNICODE
11         #pragma comment(lib,"..\\..\\duilib-master\\Lib\\Duilib_u.lib")
12     #else
13         #pragma comment(lib,"..\\..\\duilib-master\\Lib\\Duilib.lib")
14     #endif
15 #endif
16 int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
17 {
18     //TODO: Input code here...
19 }

    3. 创立窗口对象实例,并调用接口Create创建窗口;

 

    4. 调用ShowWindow显示当前窗口界面;

 

    5. 调用CPaintManagerUI的静态成员MessageLoop,执行信息循环;

  这样,Duilib已经打响并以项目DuiFarm项目中了。注意作者项目之文书结构,引用Duilib.h与Duilib_x.lib文件使用相对路径必须科学(,相对路径以DuiFarm下Debug目录内啊参照)。

    6. 卸载COM组件。

  于编写其他代码之前,需要明确几个知识点。Duilib的几个放对象。

  以上几乎只简单的步子多是兼备duilib应用程序的实施大体框架;而尽要的实际Create、MessageLoop;

  1. CWindowWnd:窗口对象父类,负责创建窗口、窗口消息过程处理、提供窗口子类化与超类化接口。
  2. CPaintManagerUI:负责窗口图形绘制。CPaintManagerUI三独第一意义:绘制控件、管理信息、事件通报。
  3. CDialogBuilder:控件布局类,主要意图:解析XML,构建控件树,创建控件对象。
  4. INotifyUI:处理事件和通告。子类重载Notify(TNotify
    &msg)虚函数,实现处理事件通知功能。
  5. CControlUI:控件管理之父类,为控件提供通用属性。

  于调用Create函数中施行了几乎独重点的操作:

 

    0. 登记窗口类、创建窗口;

  2.Starting coding “Hello World”

    1.
触发WM_CREATE消息(事实上还发其他的音讯,但少先凭需关注), 创建控件构造器CDialogBuilder,并以那中间CMarkup解析指定的test1.xml文书,并解析XML文件各节点;

  于DuiFarm.cpp中初建类DuiFarm,继承自CWindowWnd与INotifyUI,重写CWindowWnd的虚函数GetWindowClassName、HandleMessage与INotify的虚函数Notify。代码如下:

    2.
分析完成后,调用构建器的_Parse接口,实现对周CMarkup各节点控件的报名、创建并盖各级控件所在xml文件中的布局集团控件树;

class DuiFarm: public CWindowWnd, public INotifyUI
{
protected:
    CPaintManagerUI m_PaintManager;
public:
    virtual LPCTSTR GetWindowClassName() const 
    {/*some code*/}
    virtual void    Notify(TNotifyUI& msg) 
    {/*some code*/}
    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    {/*some code*/}
};

    3.
于构建了控件树后,得到树根控件并由此CPaintManagerUI绘制UI管理器的接口AttachDialog添加至绘制管理受到;

  其中老三只函数的主要成效:

    4.
通过AddNotifier添加通告对象及CPaintManagerUI中,以便让可接受通知消息,触发void
Notify(TNotifyUI& msg)调用,用户可以该触发被举行有响应操作;

  1. GetWindowClassName:返回窗口名称。
  2. Notify:事件响应,如点击事件。
  3. HandleMessage:处理消息,例如创建窗口消息。

  所以以上之几个操作多完成了亟需绘制和控件响应的核心原则;

  首先补充全GetWindowClassName函数的代码,在函数体内,直接返回窗体名字符串。

  于调用MessageLoop中,实现信息循环(先忽略我们无极端谢谢兴趣之信息):

virtual LPCTSTR GetWindowClassName() const 
{return _T("DuiFramFrame");}

    0.
收到WM_PAINT消息,在里头先成功了通消息windowinit,使得触发Notify,此时得做一些初始化操作;

  HandleMessage函数中上全针对窗体创建等消息之处理。

    1.
另外创建窗体的配合DC、兼容位图;接着要之是调用m_pRoot->DoPaint(m_hDcOffscreen,
ps.rcPaint);此调用将不辱使命具有给管理之控件树位置计算、绘制到相当DC;

 1 virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
 2 {
 3     LRESULT lRes = 0;
 4     if( uMsg == WM_CREATE ) 
 5     {
 6         m_PaintManager.Init(m_hWnd);    //init dialog paint
 7         CDialogBuilder builder;        
 8         /* load xml, create widget obj, draw dialog */
 9         CControlUI *pRoot = builder.Create(_T("dui-design.xml"),(UINT)0,NULL,&m_PaintManager);
10         ASSERT(pRoot&&"### XML error!");
11         m_PaintManager.AttachDialog(pRoot);    //widget attach to dialog
12         m_PaintManager.AddNotifier(this);      //add msg notify to window
13         return lRes;
14     }
15     if( m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes)) 
16     {
17         return lRes;
18     }
19     return __super::HandleMessage(uMsg, wParam, lParam);
20 }

    2.
然后调用BitBlt实现兼容DC到窗体DC的位块传输、拷贝并求任何窗体重绘;

  第4实施在消息吧窗体创建(WM_CREATE)时,执行:

  OK,以上两个举足轻重操作就了颇具的根本成效包括xml文件分析,控件树的开创,绘制的军事管制、贴图,控件消息应等;

  1. 初始化当前窗口绘制(line 6)
  2. 加载窗口设计xml文件,初始化窗口部件(line 9)
  3. 窗口部件对象附着对话框(line 11)
  4. 累加消息通知(line 12)

  为咱们知道duilib中逐条控件是不曾窗体句柄的,那么接下,我们继续羁押各个控件对应的各种信息是什么样为查获和传递的;

  执行了上述代码,窗体即绘制就,事件通报曾可用。在上述代码中,第8实施加载xml文件就为duilib的界面设计xml。犹如html之被浏览器,dui通过解析xml将控件绘制到窗体上。

    首先我们为该工程中之OnAlphaChanged接口说明,我们用倒叙跟踪的点子;

  xml文件如下:

    1.
拖欠接口在OnPrepare接口中叫填补加到一个被称“alpha_controlor”的控件对象的OnNotify通告消息函数中,而OnPrepare函数在Notify接口中于调用,被调用的空子也

1 <?xml version="1.0" encoding="utf-8"?>
2 <Window size="100,100">
3   <HorizontalLayout bkcolor="#FFFFFF00">
4     <Button name="btnHello" text="Hello World :-)"/>
5   </HorizontalLayout>
6 </Window>

    MessageLoop中收到WM_PAINT时候做到的打招呼消息windowinit;

  将文件保留至花色Debug目录下(因眼前种因为Debug模式运作)。这段xml描述了窗体的完全布局:

    2.
当鼠标左击按下经常,CPaintManagerUI将吸收WM_LBUTTONDOWN消息,所以我们要规定点击位于哪个控件上,跟踪该信息,内部通过WM_LBUTTONDOWN消息对应之

  • 老二执行定义了窗体大小,长宽各500诸如从。
  • 老三履定义了一个横向布局,背景黄色(bkcolor为背景色设置)。
  • 季行定义了一个按钮,名称是btnHello,显示文字吗Hello World 🙂

    lParam参数获取到鼠标点击的职务,并由此FindControl查找到指定的鼠标位置下控件(整个查找过程吧遍历当前控件以及其下所有子控件,每个控件根据自己的岗位及鼠标的岗位确定

  现在窗体已经定义好,需要添加对按钮事件的拍卖。根据达平等篇介绍,按钮事件处理要以重载的Notify函数中编。

    是否也投机并返自己);

1 virtual void Notify(TNotifyUI& msg) 
2 {
3     if(msg.sType==_T("click"))
4     {
5         if(msg.pSender->GetName()==_T("btnHello"))
6             ::MessageBox(NULL,_T("Hello World :-)"),_T("Hallo Welt :-D"),NULL);
7     }
8 }

    3.
针对得到的控件,调用该控件的SetFocus以及Event,在SetFocus中调用CPaintManagerUI的SetFocus构造TEventUI(一般用CPaintManagerUI的信转化为duilib自定义之控件的音)

  • 第2实施代码表示:“此处设吸收类型为‘click’的事件”。
  • 第5尽代码表示:“在有click事件备受,此处就接到名也‘btnHello’这家伙的风波”。
  • 第6履行代码表示:“提示英德比的Hello World,以及她对应的口型”。

    并调用SendNotify,这样虽触发了针对性承诺控件的通告消息并最终调用到OnAlphaChanged;在调用控件的Event时重组织TEventUI结构参数,调用DoEvent完成点事件响应;

  编写到此处,项目就有所窗口绘制、窗口布局以及事件处理的基本功能,下面用以入口函数中吗之新始化与分配资源:

  OK,目前基本上就了解了控件的音讯数据流及其响应,以及控件绘制,不过当单个控件无效需要重绘时无应当调用耗费很十分开支的WM_PAINT来促成有的控件重绘这一定是不得法的,所以

 1 int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
 2 {
 3     CPaintManagerUI::SetInstance(hInstance);
 4     CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath());
 5     DuiFarm duiFarm;
 6     duiFarm.Create(NULL, _T("Dui Farm"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
 7     duiFarm.CenterWindow();
 8     duiFarm.ShowModal();
 9     return 0;
10 }

  对于一些控件若无涉及到全体或是其他控件重绘的用直指向一一控件内部调整位置、状态,然后调用CPaintManagerUI的Invalidate进行区域性的重绘即可。

  • 第3行~第4执行,入口函数对实例和资源开展分红,第4行实参为当前档路线。
  • 第6实践:创建窗口。
  • 第7履:设置窗口以屏幕在中。
  • 第8尽:显示窗口。

  最后一步,再称CPaintManagerUI::MessageLoop;

  于调节运行前,需要肯定DuiLib[x].dll是否位于DuiFarm项目的Debug目录下(x为_d,_ud或不设有,根据项目编码和是否也Debug模式而定)。

    0.
在创建窗口的经过遭到貌似会事先登记窗口过程函数CWindowWnd::__WndProc,并保存窗口句柄和目标;那么可看信被移、翻译与分发后还见面优先向该处理函数发送并调用;

  运行效果如下:

    1.
调用本窗口类对象的HandleMessage接口,实现信息可以以看似对象中接并拍卖;

  图片 1

    2.
HandleMessage接口中先行拍卖好感兴趣的消息,若不处理则交由CPaintManagerUI对象的MessageHandler处理;

祈求2.2.1 显示窗体

    3.
MessageHandler中会预先过来、预处理局部注册的消息;其他部分信息处理并转发为duilib的信息并执行有通、事件相当操作,若MessageHandler未处理的尽管交由CWindowWnd的

  如图,窗体显示黄色,而按钮实际上占据了百分之百窗体。点击按钮如下:

    HandleMessage,事实上该内部通过::CallWindowProc调用默认窗口过程处理函数::DefWindowProc进行大多数的默认处理(windows会自行并成立地处理,可不用关心);

图片 2

    4.
然而以上步骤是否真只有这些,肯定不止;继续跟CPaintManagerUI::MessageLoop实现;

祈求2.2.2 点击按钮(按钮占据了整整窗体)

    5.
该消息循环中当消息给翻、转化前先行调用了CPaintManagerUI::TranslateMessage,该函数内部先预处理就登记之事先处理消息及加速器消息,并冲需要确定是否处理要持续传递;

   通过以上代码,笔者实现了一个不过简单易行的Duilib窗体界面——一个窗体,一个铺满了全体窗口区域的色情按钮(由xml定义可知,窗体显示“HelloWorld
:-)”的一部分是Windows按钮)。

    6.
于其非处理的音,才会调用::TranslateMessage和::DispatchMessage翻译、分发该消息,而其后才会履行上述手续的0~3。以上就为拥有的窗体消息执行流程。

  Duilib三有的分业务及显:XML、(XML-)UI引擎、Win32,并且Duilib可以退出传统Windows界面限制,开发有别具一格的UI界面风格。我们经过重写HandleMessage函数来落实简单的无边界窗口:

  

 1 virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
 2 {
 3     LRESULT lRes = 0;
 4     if( uMsg == WM_CREATE ) 
 5     {
 6         m_PaintManager.Init(m_hWnd);    //init dialog paint
 7         CDialogBuilder builder;        
 8         /* load xml, create widget obj, draw dialog */
 9         CControlUI *pRoot = builder.Create(_T("dui-design.xml"),(UINT)0,NULL,&m_PaintManager);
10         ASSERT(pRoot&&"### XML error!");
11         m_PaintManager.AttachDialog(pRoot);    //widget attach to dialog
12         m_PaintManager.AddNotifier(this)    ;//add msg to window
13         return lRes;
14     }
15     /* blocked message: WM_NCACTIVATE,WM_NCCALCSIZE,WM_NCPAINT*/
16     else if(uMsg == WM_NCACTIVATE)
17     {
18         if(!::IsIconic(m_hWnd))
19             return (wParam == 0)?TRUE:FALSE;
20     }
21     else if(uMsg == WM_NCCALCSIZE || uMsg == WM_NCPAINT)
22     {
23         return 0;
24     }
25     if( m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes)) 
26     {
27         return lRes;
28     }
29     return __super::HandleMessage(uMsg, wParam, lParam);
30 }

  项目总:

 

    duilib整体达标因无HWND的情况下自绘完成界面绘制显示,各个控件完成自己之绘图并由此贴图的主意实现一体窗体的绘图;另外利用对缓冲区绘制界面避免了闪烁,此外针对某控件失效重绘

  通过者代码第15行~28行,屏蔽WM_NCACTIVATE,WM_NCCALCSIZE,WM_NCPAINT三只信息,实现无疆界窗体设计。显示与点击效果使图:

  也是采用句柄重绘的方法大的回落绘制出;通过XML文件配置界面布局、内容,比较灵敏可扩大,用户可根据需要改源码和增感兴趣之特性实现,很多时段用户只待把大气日因此在应用层、

图片 3

  业务逻辑层;内部各级控件资源管理统一并中贯彻协调的资源管理暨局部效能组件,使得可免需要凭STL、MFC、BOOST等,移植者不得不是windows系列或以上版本,但万一移植到其它平台则也急需

 

  花费大充分之时光与工作量;另外即使是资源路、加载,因中CPaintManagerUI保存也静态变量,所以和一个先后要MFC中需要多地处创建duilib窗口或引致资源混乱的景,可统一资源路或涂改源码

   以实际上软件开发过程被,显示与事务分别是软件开发的指导性思想,UI与工作分别使得软件开发工作再次好之分割业务范围。与原来的出模式相比,XML定义界面相比C++代码定义界面更加从简方便,后台开发人员可以由界面设计、图片图标呈现等非本专业工作面临解放出来,专注让业务逻辑和数据处理;美工与UI设计人员注意让界面美化而毋庸顾及后台兼容性问题。Duilib通过xml解析、对象创建、部件附着将复杂的UI设计包装到可安排的库中,完全依据win32阳台若开发人员不必别学一栽技术,从而避免了“重新造轮子”给程序员带来额外的学成本开销。

  实现为化解该问题;当然最好要紧之凡娇小、轻便、资源可以包,可组合打包工具轻松打安装包,分发给最终用户;但里边一些控件绘制、数据处理等细节方面比多或者还在BUG等不足;

    duilib相对于MFC不待极多靠以及大的零件库;相对于老纯WIN32开发再迅捷,用户可依据需要、项目规模以及职能要求选择该类型作为开发界面库。

    uilib应为duilib原身,整体布局同样;相对duilib,uilib会多片控件如动画、图表、GIF动画等,CDxAnimationUI、CDuiTimer、CAnimationTabLayoutUI、以及任何的工具、

  托盘CDuiTrayIcon、CDuiAutoComplete、阴影CShadowUI等等,不过以运用与知名度及duilib更为常见,可依据需要移植uilib的一部分实现到duilib以满足急需,在类型受到建议采用duilib。