在上篇中我们手写了一个界面,并在上面添加了两个按钮,在收到WM_CREATE
消息后,创建界面。一般界面包含很多个控件,而且界面经常发生变化,如果还是手写的画,显然不现实。
在duilib中可以使用xml来描述界面,框架通过解析xml,创建界面,这和我们手动写xml的效果是一样的。使用xml来描述界面,实现了界面和界面处理逻辑的分离。
这种界面和界面处理逻辑分离的方式其实和Qt是一样的,Qt 使用的是.ui
文件(实质上是xml格式的文件)来描述界面。
在duilib源码中的属性列表.xml
这个文件描述了duilib支持解析的元素和属性。以Button
为例:
<Button parent="Label" notifies="setfocus killfocus timer menu click windowinit(root)">
<Attribute name="name" default="" type="STRING" comment="控件名字,同一窗口内必须唯一,如(testbtn)"/>
<Attribute name="pos" default="0,0,0,0" type="RECT" comment="位置,如果为float控件则指定位置和大小,否则只指定大小,如(0,0,100,100)"/>
<Attribute name="padding" default="0,0,0,0" type="RECT" comment="外边距,如(2,2,2,2)"/>
<Attribute name="bkcolor" default="0x00000000" type="DWORD" comment="背景颜色,如(0xFFFF0000)"/>
<Attribute name="bkcolor2" default="0x00000000" type="DWORD" comment="背景渐变色2,和bkcolor配合使用,如(0xFFFFFF00)"/>
...省略很多...
</Button>
他的父节点为Label
控件,他的属性有name
,pos
,padding
,bkcolor
等。
属性名、默认值、值的类型、属性的用途都在属性列表.xml
有描述。
我们编写界面xml时要根据属性列表.xml
。
我们用xml这么描述上篇手写的界面:
<?xml version="1.0" encoding="UTF-8"?>
<Window size="800,600"> <!-- 窗口的初始尺寸 -->
<HorizontalLayout bkcolor="#FF00FF00"> <!-- 整个窗口的背景 -->
<Button name="btnHello1" pos="30,80,0,0" width="70" height="30" text="btnHello1"/> <!-- 按钮的属性,如名称、文本 -->
<Button name="btnHello2" pos="120,80,0,0" width="70" height="40" text="btnHello2"/>
</HorizontalLayout>
</Window>
创建窗口时的对应代码要修改为:
if (uMsg == WM_CREATE)
{
m_PaintManager.Init(m_hWnd);
CDialogBuilder builder;
CControlUI* pRoot = builder.Create(_T("duilib.xml"), (UINT)0, NULL, &m_PaintManager);
ASSERT(pRoot && "Failed to parse XML");
m_PaintManager.AttachDialog(pRoot);
m_PaintManager.AddNotifier(this);
return lRes;
}
同时我们要设置xml的路径:
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
CPaintManagerUI::SetInstance(hInstance);
// 设置资源的默认路径(此处设置为和exe在同一目录)
CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetCurrentPath()+"\\Debug");
CDuiFrameWnd duiFrame;
duiFrame.Create(NULL, _T("DUIWnd"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
duiFrame.CenterWindow(); // 启动居中;
duiFrame.ShowModal();
return 0;
}
大家可能觉得,手写界面xml也很麻烦,看效果也不是很方便,网友还是提供了一些ui设计工具,比如DuiDesigner,通过工具操作,可以帮助我们生成xml,还可以预览效果。
其实对比下Qt的代码:
class dlg_login : public QDialog
{
Q_OBJECT
public:
dlg_login(QWidget *parent = Q_NULLPTR);
~dlg_login();
signals:
void mainWndLogin();
private slots:
void OnLogin();
void showLoginWnd();
private:
void InitEvent();
private:
Ui::dlg_login ui;
};
duilib的业务代码:
class CDuiFrameWnd : public CWindowWnd, public INotifyUI
{
public:
virtual LPCTSTR GetWindowClassName() const;
virtual void Notify(TNotifyUI& msg);
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
CPaintManagerUI m_PaintManager;
};
是不是有点类似呢?CPaintManagerUI m_PaintManager
相当于Ui::dlg_login ui;
他们都是用来管理ui上的控件。
不同的是Qt的通信机制使用的是信号槽,而duilib使用的是windows消息。