My first Duilib program

  1. Prepare for development

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

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

  在DuiFarm.cpp文件首引入头文件UIlib.h,并引用namespace,及相关预编译指令。如下:

 #include "..\\..\\duilib-master\\DuiLib\\UIlib.h"
 using namespace DuiLib;
 #ifdef _DEBUG
     #ifdef _UNICODE
         #pragma comment(lib,"..\\..\\duilib-master\\Lib\\Duilib_ud.lib")
     #else
         #pragma comment(lib,"..\\..\\duilib-master\\Lib\\Duilib_d.lib")
     #endif
 #else
     #ifdef _UNICODE
         #pragma comment(lib,"..\\..\\duilib-master\\Lib\\Duilib_u.lib")
     #else
         #pragma comment(lib,"..\\..\\duilib-master\\Lib\\Duilib.lib")
     #endif
 #endif
 int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
 {
     //TODO: Input code here...
 }

  这样,Duilib已经成功集成在项目DuiFarm项目中了。注意作者项目的文件结构,引用Duilib.h与Duilib_x.lib文件使用相对路径必须正确(,相对路径以DuiFarm下Debug目录内为参照)。

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

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

  2.Starting coding "Hello World"

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

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*/}
};

  其中三个函数的主要功能:

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

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

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

  HandleMessage函数中补全对窗体创建等消息的处理。

 virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     LRESULT lRes = ;
     if( uMsg == WM_CREATE )
     {
         m_PaintManager.Init(m_hWnd);    //init dialog paint
         CDialogBuilder builder;
         /* load xml, create widget obj, draw dialog */
         CControlUI *pRoot = builder.Create(_T(,NULL,&m_PaintManager);
         ASSERT(pRoot&&"### XML error!");
         m_PaintManager.AttachDialog(pRoot);    //widget attach to dialog
         m_PaintManager.AddNotifier(this);      //add msg notify to window
         return lRes;
     }
     if( m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))
     {
         return lRes;
     }
     return __super::HandleMessage(uMsg, wParam, lParam);
 }

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

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

  执行完上述代码,窗体即绘制完成,事件通知已可用。在上述代码中,第8行加载xml文件即为duilib的界面设计xml。犹如html之于浏览器,dui通过解析xml将控件绘制到窗体上。

  xml文件如下:

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

  将文件保存到项目Debug目录下(因当前项目以Debug模式运行)。这段xml描述了窗体的整体布局:

  • 第二行定义了窗体大小,长宽各500像素。
  • 第三行定义了一个横向布局,背景黄色(bkcolor为背景色设置)。
  • 第四行定义了一个按钮,名称是btnHello,显示文字为Hello World :-)

  现在窗体已经定义好,需要添加对按钮事件的处理。根据上一篇介绍,按钮事件处理要在重载的Notify函数中编写。

 virtual void Notify(TNotifyUI& msg)
 {
     if(msg.sType==_T("click"))
     {
         if(msg.pSender->GetName()==_T("btnHello"))
             ::MessageBox(NULL,_T("Hello World :-)"),_T("Hallo Welt :-D"),NULL);
     }
 }
  • 第2行代码表示:“此处要接收类型为‘click’的事件”。
  • 第5行代码表示:“在所有click事件中,此处仅接收名为‘btnHello’这家伙的事件”。
  • 第6行代码表示:“提示英德对照的Hello World,以及它们对应的口型”。

  编写到这里,项目已经具备窗口绘制、窗口布局和事件处理的基本功能,下面需要在入口函数中为之初始化与分配资源:

 int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
 {
     CPaintManagerUI::SetInstance(hInstance);
     CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath());
     DuiFarm duiFarm;
     duiFarm.Create(NULL, _T("Dui Farm"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
     duiFarm.CenterWindow();
     duiFarm.ShowModal();
     ;
 }
  • 第3行~第4行,入口函数对实例和资源进行分配,第4行实参为当前项目路径。
  • 第6行:创建窗口。
  • 第7行:设置窗口在屏幕居中。
  • 第8行:显示窗口。

  在调试运行前,需要确认DuiLib[x].dll是否位于DuiFarm项目的Debug目录下(x为_d,_ud或不存在,根据项目编码以及是否为Debug模式而定)。

  运行效果如下:

  

图2.2.1 显示窗体

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

图2.2.2 点击按钮(按钮占据了整个窗体)

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

  Duilib三部分分割业务与显示:XML、(XML-)UI引擎、Win32,并且Duilib可以脱离传统Windows界面限制,开发出独具特色的UI界面风格。我们通过重写HandleMessage函数来实现简单的无边界窗口:

 virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     LRESULT lRes = ;
     if( uMsg == WM_CREATE )
     {
         m_PaintManager.Init(m_hWnd);    //init dialog paint
         CDialogBuilder builder;
         /* load xml, create widget obj, draw dialog */
         CControlUI *pRoot = builder.Create(_T(,NULL,&m_PaintManager);
         ASSERT(pRoot&&"### XML error!");
         m_PaintManager.AttachDialog(pRoot);    //widget attach to dialog
         m_PaintManager.AddNotifier(this)    ;//add msg to window
         return lRes;
     }
     /* blocked message: WM_NCACTIVATE,WM_NCCALCSIZE,WM_NCPAINT*/
     else if(uMsg == WM_NCACTIVATE)
     {
         if(!::IsIconic(m_hWnd))
             )?TRUE:FALSE;
     }
     else if(uMsg == WM_NCCALCSIZE || uMsg == WM_NCPAINT)
     {
         ;
     }
     if( m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))
     {
         return lRes;
     }
     return __super::HandleMessage(uMsg, wParam, lParam);
 }

  通过上面代码第15行~28行,屏蔽WM_NCACTIVATE,WM_NCCALCSIZE,WM_NCPAINT三个消息,实现无边界窗体设计。显示和点击效果如图:

  在实际软件开发过程中,显示与业务分离是软件开发的指导性思想,UI与业务分离使得软件开发工作更好的划分业务范围。与原始的开发模式对比,XML定义界面相比C++代码定义界面更加简洁便利,后台开发人员可以从界面设计、图片图标呈现等非本专业工作中解放出来,专注于业务逻辑和数据处理;美工与UI设计人员专注于界面美化而不必顾及后台兼容性问题。Duilib通过xml解析、对象创建、部件附着将复杂的UI设计封装到可配置的库中,完全基于win32平台使开发人员不必另学一种技术,从而避免了“重新造轮子”给程序员带来额外的学习成本开销。

Duilib第一步(II)-Hello World的更多相关文章

  1. Duilib第一步(I)-简介与环境搭建

    Primus gradus et cognoscetis veritatem et veritas liberabit vos.  --Johannes 8:32 Introduction Duili ...

  2. Duilib第一步(III)-知识进阶

    核心模块 CWindowWnd:窗口对象管理父类 创建窗口. 窗口消息过程处理. 提供窗口子类化.超类化接口. CDialogBuilder:空间布局类 解析XML界面布局文件,构建控件树 创建控件对 ...

  3. 开发thinkphp的第一步就是给Application目录(不包括其下的文件)777权限, 关闭selinux

    开发thinkphp的时候, 总是会出现各种个样 的奇怪的毛病, 比如: 说什么Application目录不可写, 比如: 说什么 _STORAGE_WRITE_ERROR, 不能生成 Runtime ...

  4. ElasticSearch第一步-环境配置

    ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticSearch第四步-查询详解 Elasti ...

  5. Scala的第一步

    第一步:学习使用Scala解释器 开始Scala最简单的方法是使用Scala解释器,它是一个编写Scala表达式和程序的交互式“shell”.在使用Scala之前需要安装Scala,可以参考 Firs ...

  6. UE4蓝图编程的第一步

    认识UE4蓝图中颜色与变量类型: UE4中各个颜色对应着不同的变量,连接点和连线的颜色都在表示此处是什么类型的变量.对于初学者来说一开始看到那么多连接点, 可能会很茫然,搞不清还怎么连,如果知道了颜色 ...

  7. STM32F407第一步之点亮LED

    STM32F407第一步之点亮LED. 要点亮LED,首先了解一下F4的GPIO模块.首先看一下STM32F4数据手册,GPIO模块的内部结构图 看上去有点复杂,不要怕,慢慢理解就可以了.对外引脚那里 ...

  8. 重制AdvanceWars第一步 -- 搞定地图

    首先来聊下高级战争吧Advance Wars,由任天堂旗下的Intelligent Systems开发的战棋游戏.初作诞生于GBA上,后来继续跟进了高战2黑洞崛,而后在下一代掌机DS上也出了三代续作高 ...

  9. 高德携手阿里云发布“LBS云”,账户打通只是第一步

    位置.游戏.视频,是公认的基于云计算的三大移动端应用方向.而今,LBS云有了更多进展,在高价值应用与云平台之间实现了资源打通和融合,高德迈出了实质性的一步. 高德地图副总裁郄建军(左)与阿里云业务总经 ...

随机推荐

  1. linkinFrame--测试项目添加git管理

    OK,前面一篇博客,已经搭建好了项目的基础的结构.现在我们添加一个简单的servlet来测试下项目能不能跑,然后在讲项目添加到coding上用git管理. 1,我们编写一个servlet,编写一个js ...

  2. JavaScript算法实现排序

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. 20165318 预备作业二 学习基础和C语言基础调查

    20165318 学习基础和C语言基础调查 技能学习经验 我们这一代人,或多或少的都上过各种兴趣班,舞蹈钢琴画画书法,我也是如此.可这些技能中,唯一能拿的出手的就是舞蹈了.按照<优秀的教学方法- ...

  4. img标签实现和背景图一样的显示效果——object-fit和object-positon

    不知大家在做前端页面的时候,有没有遇到类似这样的问题:有一个不是正方形的图片,可能是宽度大于高度的,也可能是高度大于宽度的,而你又并不想用背景图的方式来做,要实现用img标签来让此图片显示出一个正方形 ...

  5. 从零开始学习前端JAVASCRIPT — 10、JavaScript基础ES6(ECMAScript6.0)

    ECMAScript 6.0(简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发 ...

  6. 有关mysql的for update以及 死锁问题

    一.先说锁的概念 锁级别: 1.行级锁: InnoDB引擎(也支持表级锁,默认是行级锁),开销大,加锁慢:会出现死锁.锁定粒度最小,发生锁冲突的概率最低,并发度最高. 2.表级锁:MylSAM引擎和M ...

  7. ajax实现异步校验

    1.ajax介绍 见过百度的搜索框吗?当你输入一个关键词,下面立马会出现一些相关的热词,这就是用ajax做到的. 2.环境设想: 有一个注册页面.jsp <span id="mess& ...

  8. 11_Python文件操作

    一.文件操作的基本流程 计算机系统分为:计算机硬件,操作系统,应用程序三部分. 我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,众 ...

  9. jQuery中的选择器及筛选器

    1.jQuery的介绍 1.jQuery是继prototype之后又一个优秀的Javascript框架.其宗旨是--WRITE LESS,DO MORE! 2.它是轻量级的js库,这是其它的js库所不 ...

  10. Halcon一日一练:图像、变量实时更新

    某些场合,我们需要刷新图像来识别图像处理过程的差异性,便于调试判断问题和预测.Halcon提供了图像刷新操作,这些操作不会改变程序的最终处理结果. 例程: **实时刷新图像 dev_update_wi ...