Duilib库(1)

Duilib库的介绍

Duilib是一款强大轻量级的界面开发工具,可以将用户界面和处理逻辑彻底分离,极大地提高用户界面的开发效率。
Duilib仅仅是基于Win32的一套UI库,并不是使用了Duilib后它就不是Win32程序了,Duilib并不像
MFC一样将所有东西全包了,它仅仅包装了UI部分。

Duilib界面库框架

Duilib的库目录中主要包含了4个目录:
1.Control:Duilib各个控件对应的UI类,比如:按钮(CButtonUI)、编辑框(CEditUI)、下拉框
(CComboBoxUI)等
2.Layout:Duilib的各种布局器所对应的UI类,比如:水平布局(CHorizontalLayoutUI)、垂直布局
(CVerticalLayoutUI)等
3.Core:Duilib库的核心操作:窗口相关(Win32流程封装–CWindowWnd)、窗口解析(CMarkup)等
4.Utils:Duilib封装的一些类型:CDUIString、CPoint、压缩等

从Win32过渡到Duilib程序

1.Duilib的环境搭建:
在项目中使用Duilib界面库之前,必须要对Duilib库进行编译,编译完成后,只需将生产的静态库和Duilib源文件目录包含到工程中,将生成的dll包含到工程目录下即可
配置完成后仅需要包含头文件即可:

#include"UIlib.h"
using namespace DuiLib;

2.Duilib创建简单的窗口
定义一个类(类名自己取),让其继承自CWindowWnd类,CWindowWnd类是Duilib封装的一个与窗口相关类。该类中封装了窗口创建所需的:注册窗口类、创建窗口、显示窗口等。重写
CWindowWnd类GetWindowClassName()虚函数,返回用户所创建窗口类的名字。

class CDuiFramWnd : public CWindowWnd
{
public:
// CWindowWnd类的纯虚函数,在该函数中必须返回用户所定义窗口的类名称,注册窗口时需要用到
virtual LPCTSTR GetWindowClassName() const
{
return _T("DuiFramWnd");
}
};
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int
nCmdShow)
{
CDuiFramWnd framWnd;
// Cashier即在窗口右上角显式的名字
// UI_WNDSTYLE_FRAME: duilib封装的宏,代表窗口可视,具有标题栏,最大化最小化,关闭功能等
// WS_EX_WINDOWEDGE: Win32的窗口风格,带有边框
framWnd.Create(NULL, _T("Cashier"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
//显示窗口,激活消息循环
framWnd.ShowModal();
return 0;
}

3.窗口增加按钮控件
窗口创建成功后,在窗口上显示一个按钮(Button)控件。该按钮控件的创建,只能是在窗口创建时,在窗口上创建好。

virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = 0;
if (uMsg == WM_CREATE)
{
// 创建一个按钮
CControlUI *pWnd = new CButtonUI;
// 设置按钮上的显示文本
pWnd->SetText(_T("Hello World"));
// 按钮的背景颜色
pWnd->SetBkColor(0xFF00FF00);
return lRes;
}
// 注意:__super为vs扩展的一个关键字,意思是调用基类的成员
// 用户将WM_CREATE消息处理后,其他消息交给其基类HandleMessage方法进行处理
return __super::HandleMessage(uMsg, wParam, lParam);
}

窗口创建好后,好像没有显示出按钮,而且窗口好像不能正常缩放,这是因为按钮控件的消息没有响应,窗口放大化没有进行重绘造成的,解决办法:
1.给CDuiFramWnd类增加CPaintManagerUI m_PaintManager;成员变量
2.在设置完按钮颜色后增加如下代码:

virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = 0;
if (uMsg == WM_CREATE)
{
CControlUI *pWnd = new CButtonUI;
pWnd->SetText(_T("Hello World"));
pWnd->SetBkColor(0xFF00FF00);
// 初始化m_PaintManager对象的窗口句柄,发送消息时需要用到
m_PaintManager.Init(m_hWnd);
// 将按钮关联到绘制管理器上
m_PaintManager.AttachDialog(pWnd);
return lRes;
}
if (m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))
{
return lRes;
}
// 注意:__super为vs扩展的一个关键字,意思是调用基类的成员
return __super::HandleMessage(uMsg, wParam, lParam);
}

此时窗口上的按钮就显式出来了,按钮占满了整个窗口。

4.按钮控件消息响应
上面hello world按钮点击后程序没有反应的原因是:该按钮的点击消息没有响应,如果想要响应按钮消息,
进行以下操作:
1.让CDuiFramWnd类继承INotifyUI。
2.按钮创建成功后,添加按钮控件消息响应到duilib的消息循环中
3.重写INotifyUI类的Notify纯虚函数,在该函数中用户捕获其想要处理的消息,进行自己想要的操作即可。

class CDuiFramWnd : public CWindowWnd, public INotifyUI
{
public:
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = 0;
if (uMsg == WM_CREATE)
{
// 。。。
// 添加控件等消息响应,这样消息就会传达到duilib的消息循环,
// 就可以在Notify函数里做消息处理
m_PaintManager.AddNotifier(this);
return lRes;
}
if (m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))
{
return lRes;
}
// 注意:__super为vs扩展的一个关键字,意思是调用基类的成员
return __super::HandleMessage(uMsg, wParam, lParam);
}
virtual void Notify(TNotifyUI& msg)
{
if (msg.sType == _T("click"))
{
MessageBox(m_hWnd, _T("Hello World"), _T("DuiFramWnd"), IDOK);
}
}
private:
CPaintManagerUI m_PaintManager;
};

至此按钮消息可以响应。

带有XML的Win32窗口

1 屏蔽系统自带标题栏
duilib其实并没有区分标题栏和客户区,它的实现方法是屏蔽了系统自带的标题栏,用客户区来模拟标题栏,所以想怎么画就怎么画,非常方便。 在HandleMessage函数里屏蔽以下三个消息即可 WM_NCACTIVATE、WM_NCCALCSIZE、WM_NCPAINT,具体如下:

virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = 0;
if( uMsg == WM_CREATE )
{
CControlUI *pWnd = new CButtonUI;
pWnd->SetName(_T("btnHello")); // 设置控件的名称,这个名称用于标识每一个控件,必须唯一,相当于MFC里面的控件ID
pWnd->SetText(_T("Hello World")); // 设置文字
pWnd->SetBkColor(0xFF00FF00); // 设置背景色
m_PaintManager.Init(m_hWnd);
m_PaintManager.AttachDialog(pWnd);
m_PaintManager.AddNotifier(this); // 添加控件等消息响应,这样消息就会传达到
duilib的消息循环,我们可以在Notify函数里做消息处理
return lRes;
}
// 以下3个消息WM_NCACTIVATE、WM_NCCALCSIZE、WM_NCPAINT用于屏蔽系统标题栏
else if( uMsg == WM_NCACTIVATE )
{
if( !::IsIconic(m_hWnd) )
{
return (wParam == 0) ? TRUE : FALSE;
}
}
else if( uMsg == WM_NCCALCSIZE )
{
return 0;
}
else if( uMsg == WM_NCPAINT )
{
return 0;
}
if( m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes) )
{
return lRes;
}
return __super::HandleMessage(uMsg, wParam, lParam);
}

2 XML格式的Win32窗口
上述创建窗口的过程还是比较复杂,没有体现到Duilib的优势,duilib主打的界面制作方式是XML + UI引擎 + win32框架,通过XML的方式来重写窗口,然后Duilib对XML进行解析,将窗口创建成功。
新建一个XML文件duilib.xml,将以下内容拷贝到文件中,然后将该文件拷贝到exe所有目录下。

<?xml version="1.0" encoding="UTF-8"?>
<Window size="800,600"> <!-- 窗口的初始尺寸 -->
<HorizontalLayout bkcolor="#FF00FF00"> <!-- 整个窗口的背景 -->
</HorizontalLayout>
</Window>

将HandleMessage中处理WM_CREATE消息中的代码替换如下:

if( uMsg == WM_CREATE )
{
m_PaintManager.Init(m_hWnd);
CDialogBuilder builder;
// duilib.xml需要放到exe目录下
CControlUI* pRoot = builder.Create(_T("duilib.xml"), (UINT)0, NULL, &m_PaintManager);
m_PaintManager.AttachDialog(pRoot);
m_PaintManager.AddNotifier(this);
return lRes;
}

在创建窗口之前,必须设置加载xml文件的路径:

CPaintManagerUI::SetInstance(hInstance);
// 设置资源的默认路径(此处设置为和exe在同一目录)
CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath())
发布了37 篇原创文章 · 获赞 3 · 访问量 1072

猜你喜欢

转载自blog.csdn.net/weixin_43264873/article/details/103424217