我们在配置好Duilib库之后。开始下一步操作。
- 首先我们需要创建一个Win32工程。
#include"UIlib.h"
引入头文件。 - 链接lib静态库。
#pragma comment(lib,"DuiLib_ud.lib")
- 包含命名空间
using namespace DuiLib;
在写代码之前我们先要了解一下,CWindowWnd类,CWindowWnd是Duilib封装的一个窗口类,主要功能为窗口创建操作。在使用该类的时候,我们需要对其GetWindowClassName函数进行重写,在该函数中必须返回用户所定义窗口的类名称,注册窗口时需要用到。
class CDuiFramWnd : public CWindowWnd
{
public:
// 在该函数中必须返回用户所定义窗口的类名称,注册窗口时需要用到
virtual LPCTSTR GetWindowClassName() const
{
return _T("DuiFramWnd");
}
};
增加按钮控件,按钮控件的显示应该是在创建窗口的时候显示出来,所以我们需要将Duilib库中的HandleMessage(消息处理函数进行重写)。
HandleMessage
class CDuiFramWnd : public CWindowWnd
{
public:
// 在该函数中必须返回用户所定义窗口的类名称,注册窗口时需要用到
virtual LPCTSTR GetWindowClassName() const
{
return _T("DuiFramWnd");
}
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
{
//创建一个按钮
CControlUI *pWnd = new CButtonUI;
// 设置按钮内容
pWnd->SetText(_T("Make Gif software")); //_T字符串类型转换
}
//处理不了的信息交给父类处理
return __super::HandleMessage(uMsg, wParam, lParam);
}
};
但是这样创建出来的按钮是没有办法显示出来的,因为这样创建的按钮没有相应处理的消息。
消息
- 系统消息
- 用户自定义消息
我们自定义的消息编译器是不认识,所以我们需要对其进行自定义处理。
解决办法:增加一个回话管理器,主要处理我们自定义的消息。
CPaintManagerUI m_PaitManager;
因此,我们只需要在HandleMessage
消息处理函数中,显示调用即可。
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
{
//创建一个按钮
CControlUI *pWnd = new CButtonUI;
// 设置按钮内容
pWnd->SetText(_T("Make Gif software")); //_T字符串类型转换
pWnd->SetBkColor(0xAAFF00FF);//设置背景色
//初始化m_PaintManager对象的窗口句柄,发送消息时需要用到
m_Pait.Init(m_hWnd);
//将按钮控件链接到回话管理器上
m_Pait.AttachDialog(pWnd);
}
LRESULT lRes = 0;
//使用绘画管理器处理自定义信息,lRes是返回值,通常设置为0
if (m_Pait.MessageHandler(uMsg, wParam, lParam, lRes))
{
return lRes;
}
//处理不了的信息交给父类处理
return __super::HandleMessage(uMsg, wParam, lParam);
}
运行截图:
上面的整个界面都是我们创建的按钮,但是我们点击这个按钮发现没有任何反应,这是由于没有将按钮的信息响应出来。
解决办法:让我们创建的CDuiFramWnd继承INotifyUI。
作用:当检测到按钮按下的信号,做出相应的动作。
我们发现INotifyUI中只有一个Notify函数,该函数的作用是用于用户捕获自定义信息,进行自定义操作。同样的我们需要将该Notify连接到绘画器中。m_Pait.AddNotifier(this);
#include"UIlib.h"
#pragma comment(lib,"DuiLib_ud.lib")
using namespace DuiLib;
class CDuiFramWnd : public CWindowWnd,public INotifyUI
{
public:
// 在该函数中必须返回用户所定义窗口的类名称,注册窗口时需要用到
virtual LPCTSTR GetWindowClassName() const
{
return _T("DuiFramWnd");
}
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
{
//创建一个按钮
CControlUI *pWnd = new CButtonUI;
// 设置按钮内容
pWnd->SetText(_T("Make Gif software")); //_T字符串类型转换
pWnd->SetBkColor(0xAAFF00FF);
//初始化m_PaintManager对象的窗口句柄,发送消息时需要用到
m_Pait.Init(m_hWnd);
//将按钮控件链接到回话管理器上
m_Pait.AttachDialog(pWnd);
//链接自定义处理消息
m_Pait.AddNotifier(this);
}
LRESULT lRes = 0;
//使用绘画管理器处理自定义信息,lRes是返回值,通常设置为0
if (m_Pait.MessageHandler(uMsg, wParam, lParam, lRes))
{
return lRes;
}
//处理不了的信息交给父类处理
return __super::HandleMessage(uMsg, wParam, lParam);
}
//捕获自定义消息,用于自定义处理
virtual void Notify(TNotifyUI& msg)
{
if (msg.sType == _T("click")) //.sType为消息类型
{
MessageBox(NULL, _T("Test_click"), _T("Test"), IDOK); //弹窗测试
}
}
private:
CPaintManagerUI m_Pait;
};
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int
nCmdShow)
{
CDuiFramWnd framWnd;
// Cashier即在窗口右上角显式的名字
// UI_WNDSTYLE_FRAME: 窗口可视的宏,具有标题栏,最大化最小化,关闭功能等
// WS_EX_WINDOWEDGE: Win32的窗口风格,带有边框
framWnd.Create(NULL, _T("Test"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
//显示窗口,激活消息循环
framWnd.ShowModal();
return 0;
}
在Duilib库中是没有明显区分客户区与标题栏的,所以我们需要自己设置标题栏,但是Win32程序自带标题栏,我们需要将其屏蔽掉,用客户区来模拟标题栏,
所以想怎么画就怎么画,非常方便。
在HandleMessage函数中只需要屏蔽WM_NCACTIVATE、 WM_NCCALCSIZE、WM_NCPAINT
三个消息即可。
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
...
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_Pait.MessageHandler(uMsg, wParam, lParam, lRes))
...
}
这下我们运行程序,我们会发现上面的标题栏没有了,这就导致一个很尴尬的问题,怎么关闭呢?
我们在.exe目录下创建一个.xml文档。
使用记事本打开,我们将下面的代码拷贝到.xml文档中。
<?xml version="1.0" encoding="UTF-8"?>
<Window size="800,600"> <!-- 窗口的初始尺寸 -->
<HorizontalLayout bkcolor="#AAFF00FF"> <!-- 整个窗口的背景 -->
</HorizontalLayout>
</Window>
将该文档的编码格式改成UTF-8。
我们将.xml文档引入到代码中。
我们只需要将.xml文档导入到HandleMessage函数中。
运行报错:由于编译器不知道.xml文档的路径,所以我门还需要在主函数中,获取其路径。
完整代码
#include"UIlib.h"
#pragma comment(lib,"DuiLib_ud.lib")
using namespace DuiLib;
class CDuiFramWnd : public CWindowWnd,public INotifyUI
{
public:
// 在该函数中必须返回用户所定义窗口的类名称,注册窗口时需要用到
virtual LPCTSTR GetWindowClassName() const
{
return _T("DuiFramWnd");
}
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
{
m_Pait.Init(m_hWnd);
CDialogBuilder builder;
CControlUI* pRoot = builder.Create(_T("makeGif.xml"), (UINT)0, NULL, &m_Pait);
m_Pait.AttachDialog(pRoot);
m_Pait.AddNotifier(this);
}
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;
}
LRESULT lRes = 0;
//使用绘画管理器处理自定义信息,lRes是返回值,通常设置为0
if (m_Pait.MessageHandler(uMsg, wParam, lParam, lRes))
{
return lRes;
}
//处理不了的信息交给父类处理
return __super::HandleMessage(uMsg, wParam, lParam);
}
//捕获自定义消息,用于自定义处理
virtual void Notify(TNotifyUI& msg)
{
if (msg.sType == _T("click")) //.sType为消息类型
{
MessageBox(NULL, _T("Test_click"), _T("Test"), IDOK); //弹窗测试
}
}
private:
CPaintManagerUI m_Pait;
};
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int
nCmdShow)
{
CPaintManagerUI::SetInstance(hInstance);
// 设置资源的默认路径(此处设置为和exe在同一目录)
CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath());
CDuiFramWnd framWnd;
framWnd.Create(NULL, _T("Test"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
//显示窗口,激活消息循环
framWnd.ShowModal();
return 0;
}
运行截图
现在我们已经完成基本的函数,我们只需要在.xml文档中进行编译,即可对软件的界面进行修改。
.xml文件,我们可以通过DuiDesigner_d.exe工具进行绘画。
或许上面的代码有点过程有点复杂。这时,我们只需要将我们创建的类继承WindowImplBase
我们先看一下WindoImplBase类中有什么:
原来在底层,WindowImplBase对CWindowWnd与INotifyUI都继承,所以我们直接继承WindowImplBase比较简单。
class CDuiFramWnd : public WindowImplBase
{
protected:
virtual CDuiString GetSkinFolder() //获取路径,由于我们已经在WinMain主函数中进行路径获取,所以返回NULL
{
return _T("");
}
virtual CDuiString GetSkinFile() //获取皮肤文件.xml名称
{
return _T("makeGif.xml");
}
virtual LPCTSTR GetWindowClassName(void) const//获取窗口类名
{
return _T("DuiWnd");
}
virtual void Notify(TNotifyUI& msg)
{
if (msg.sType == _T("click"))
{
MessageBox(m_hWnd, _T("Hello World"), _T("DuiFramWnd"), IDOK);
}
}
};
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int
nCmdShow)
{
CPaintManagerUI::SetInstance(hInstance);
// 设置资源的默认路径(此处设置为和exe在同一目录)
CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath());
CDuiFramWnd framWnd;
framWnd.Create(NULL, _T("Test"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
framWnd.CenterWindow(); //窗口居中显示
//显示窗口,激活消息循环
framWnd.ShowModal();
return 0;
}