一.Duilib开发之基本使用

一. Duilib介绍

Duilib是一款轻量级,遵循BSD协议的开源C++ GUI框架,可以免费用于商业项目,是由杭州月牙儿网络技术有限公司基于DirectUI界面思想设计出来的GUI开源框架;所谓的DirectUI思想其实指的就是窗口只有一个,而窗体上面的所有东西(控件)都是绘制上去的(逻辑窗体,并不是真正意义上面的窗体控件,它是没有句柄的),而传统GUI程序,你所看到的任何一个控件其实本质都是一个窗体,只不过做成了某种功能控件(有句柄的),也就是所见一切皆窗体!

二. Duilib配置

1. Duilib版本下载

Duilib原版版本: https://github.com/duilib/duilib.//原版的
Duilib旗舰版本: https://gitee.com/qdtroy/DuiLib_Ultimate.//群维护
网易版,腾讯版等…

2. Duilib目录结构

//以Duilib原版版本作为介绍
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. Duilib源码编译

  1. 打开.sln解决方案:直接编译Duilib,QQDemo!
  2. Duilib解决方案下:bin目录找到QQDemo_d.exe运行就可以看到效果!

三. Duilib使用

1. 创建空解决方案

创建一个空的vs2013解决方案,在解决方案下创建一个Reference目录,这个目录就专门用来存放第三方库!

2. 加入Duilib工程

将Duilib工程放进去,打开解决方案,添加现有项目Duilib工程,配置并编译!

3. 静态编译Duilib

在这里插入图片描述
在这里插入图片描述

4. 简单-使用Duilib

  1. 创建Win32项目(删除多余代码 留空main函数)
// DuilibDemo.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "DuilibDemo.h"

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);



	return 0;
}

  1. 引用Duilib头文件所在目录/库文件所在目录
    在这里插入图片描述
    在这里插入图片描述
  2. 创建Duilib Win32 窗体!
    //CWindowWnd其实就是Duilib对纯Win32窗体的封装,创建Win32窗体,不支持Duilib界面特性(它可不认识和支持什么XML加载界面)!
#pragma once

#include "UIlib.h"

#ifdef _DEBUG
#pragma comment(lib,"Duilib_d.lib")
#else
#pragma comment(lib,"Duilib.lib")
#endif

using namespace DuiLib;

class CDuilibWin32Wnd :public CWindowWnd
{
public:
	CDuilibWin32Wnd();
	~CDuilibWin32Wnd();

protected:
	virtual LPCTSTR GetWindowClassName() const = 0;
};


#include "stdafx.h"
#include "DuilibWin32Wnd.h"


CDuilibWin32Wnd::CDuilibWin32Wnd()
{
}


CDuilibWin32Wnd::~CDuilibWin32Wnd()
{
}

LPCTSTR CDuilibWin32Wnd::GetWindowClassName() const
{
	return L"DuilibWin32Window";
}

// DuilibDemo.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "DuilibDemo.h"
#include "DuilibWin32Wnd.h"

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	::CoInitialize(NULL);
	CPaintManagerUI::SetInstance(hInstance);
	//Duilib win32 窗体:

	CDuilibWin32Wnd duilibWin32Wnd;
	HWND hDuiWin32Wnd = duilibWin32Wnd.Create(NULL, L"DuilibWin32Wnd", WS_OVERLAPPEDWINDOW, NULL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL);
	if (hDuiWin32Wnd == NULL)
	{
		MessageBox(NULL, L"DuilibWin32窗体创建失败!", L"Err", MB_OK);
		return false;
	}
	duilibWin32Wnd.CenterWindow();
	duilibWin32Wnd.ShowWindow(SW_SHOW);
	
	CPaintManagerUI::MessageLoop();
	::CoUninitialize();

	return 0;
}

  1. 创建Duilib 支持XML 窗体
    //WindowImplBase是Duilib在纯Win32窗体类的基础上融入Duilib特性(支持XML加载界面),给我们实现的一个支持Duilib特性的窗体类!(这样的一个Duilib窗体类,我们完全是可以自己写的)
    exe运行目录:创建skin目录,书写XML界面文件(demo.xml)
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Window size="668,469" caption="0,0,0,56" roundcorner="4,4">
	<Font id="0" name="微软雅黑" size="12"/>
	<Font id="1" name="微软雅黑" size="14"/>
	<Font id="2" name="微软雅黑" size="16"/>
	<Font id="3" name="微软雅黑" size="18"/>
	<VerticalLayout bkcolor="#FFFFFFFF">
		<HorizontalLayout name="ListContainer" vscrollbar="true" >
			<List name="list_data">
				<ListContainerElement pos="0,0,400,30" minheight="30" maxheight="30" mouse="true" mousechild="true" bordersize="1">
					<HorizontalLayout>
						<HorizontalLayout>
							<VerticalLayout>
							<Control />
							<Button name="sectionNameBtn" height="20" text="button" align="left" textcolor="#FF0000FF" font="4" padding="20,0,0,0" focusedtextcolor="#FF00FF00" pushedtextcolor="#FFFF0000" />
							<Control />
							</VerticalLayout>
						</HorizontalLayout>
						<HorizontalLayout width="120">
							<Label name="DurationLabel" text="label" align="center" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" />            
						</HorizontalLayout>
						<HorizontalLayout width="60">				
							<VerticalLayout>
								<Control />
								<Button name="playSectionBtn" text="play" align="center" width="50" height="20" font="1" bkcolor="#FF0090F0" textcolor="#FFFFFFFF"/>
								<Control />
							</VerticalLayout>
						</HorizontalLayout>
					</HorizontalLayout>	
				</ListContainerElement>				
			</List>
		</HorizontalLayout>
	</VerticalLayout>
</Window>
#pragma once

#include "UIlib.h"

#ifdef _DEBUG
#pragma comment(lib,"Duilib_d.lib")
#else
#pragma comment(lib,"Duilib.lib")
#endif

using namespace DuiLib;

class CDuilibXMLWnd : public WindowImplBase
{
public:
	CDuilibXMLWnd();
	~CDuilibXMLWnd();

protected:
	virtual CDuiString GetSkinFolder();
	virtual CDuiString GetSkinFile();
	virtual LPCTSTR GetWindowClassName(void) const;
};
#include "stdafx.h"
#include "DuilibXMLWnd.h"


CDuilibXMLWnd::CDuilibXMLWnd()
{
}


CDuilibXMLWnd::~CDuilibXMLWnd()
{
}

CDuiString CDuilibXMLWnd::GetSkinFolder()
{
	return L"./skin";
}

CDuiString CDuilibXMLWnd::GetSkinFile()
{
	return L"Demo.xml";
}

LPCTSTR CDuilibXMLWnd::GetWindowClassName(void) const
{
	return L"DuilibXMLWindow";
}

// DuilibDemo.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "DuilibDemo.h"
#include "DuilibWin32Wnd.h"
#include "DuilibXMLWnd.h"

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	::CoInitialize(NULL);
	CPaintManagerUI::SetInstance(hInstance);
	//Duilib win32 窗体:

	//CDuilibWin32Wnd duilibWin32Wnd;
	//HWND hDuiWin32Wnd = duilibWin32Wnd.Create(NULL, L"DuilibWin32Wnd", WS_OVERLAPPEDWINDOW, NULL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL);
	//if (hDuiWin32Wnd == NULL)
	//{
	//	MessageBox(NULL, L"DuilibWin32窗体创建失败!", L"Err", MB_OK);
	//	return false;
	//}
	//duilibWin32Wnd.CenterWindow();
	//duilibWin32Wnd.ShowWindow(SW_SHOW);

	CDuilibXMLWnd duilibXMLWnd;
	HWND hDuiXMLWnd = duilibXMLWnd.Create(NULL, L"DuilibXMLWnd", WS_OVERLAPPEDWINDOW, NULL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL);
	if (hDuiXMLWnd == NULL)
	{
		MessageBox(NULL, L"DuilibXMLWnd窗体创建失败!", L"Err", MB_OK);
		return false;
	}
	duilibXMLWnd.CenterWindow();
	duilibXMLWnd.ShowWindow(SW_SHOW);
	
	CPaintManagerUI::MessageLoop();
	::CoUninitialize();

	return 0;
}

  1. 实现Duilib 如何从原生Win32窗体(CWindowWnd)演变成支持Duilib特性(实现:WindowImplBase)的Duilib窗体!
//.h
//1.继承CWindowWnd 重写GetWindowClassName纯虚函数
class CBaseDuilibWnd :public CWindowWnd
{
public:
	CBaseDuilibWnd();
	~CBaseDuilibWnd();
protected:	
	virtual LPCTSTR GetWindowClassName() const;
private:
	//创建Duilib UI管理器
	CPaintManagerUI m_pUI;
};
//2.重写HandleMessage 接收处理窗口过程消息
class CBaseDuilibWnd :public CWindowWnd
{
public:
	CBaseDuilibWnd();
	~CBaseDuilibWnd();
	//
protected:	
	virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
	//处理消息
	virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	virtual LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	//
	virtual LPCTSTR GetWindowClassName() const;
private:
	CPaintManagerUI m_pUI;
};
//.cpp
LRESULT CBaseDuilibWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	LRESULT lRes = 0;
	BOOL bHandled = TRUE;
	switch (uMsg)
	{
	//创建窗体
	case WM_CREATE:
		lRes = OnCreate(uMsg, wParam, lParam, bHandled);
		break;
	//销毁窗体
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		bHandled = FALSE;
	}


	if (bHandled)
	{
		return lRes;
	}
	//消息流向Duilib消息处理
	if (m_pUI.MessageHandler(uMsg, wParam, lParam, lRes))
		return lRes;
	//消息流向系统默认处理
	return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
}
...
//处理窗体创建消息WM_CREATE:
LRESULT CBaseDuilibWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	//窗体句柄给UI管理器
	m_pUI.Init(m_hWnd);
	//创建XML解析器
	CDialogBuilder builder;
	//解析并返回根UI节点
	CControlUI* pRoot = builder.Create(_T("Demo.xml"), (UINT)0, NULL, &m_pUI);
	ASSERT(pRoot && "Failed to parse XML");
	//将根节点加入UI管理器
	m_pUI.AttachDialog(pRoot);
	return 0;
}
#include "stdafx.h"
#include "DuilibDemo.h"
#include "BaseDuilibWnd.h"

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);
	//Duilib用到了COM所以需要进行COM初始化和销毁
	::CoInitialize(NULL);
	CPaintManagerUI::SetInstance(hInstance);
	
	/*custom XML Duilib 窗体*/
	//设置资源路径 自己手写Duilib窗体类 skin放DuilibDemo工程目录或者将运行目录设置为exe所在目录
	DuiLib::CPaintManagerUI::SetResourcePath(TEXT("./skin"));

	CBaseDuilibWnd duilibBaseWnd;
	HWND hDuiXMLWnd = duilibBaseWnd.Create(NULL, L"DuilibBaseWnd", WS_OVERLAPPEDWINDOW, NULL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL);
	if (hDuiXMLWnd == NULL)
	{
		MessageBox(NULL, L"DuilibBaseWnd窗体创建失败!", L"Err", MB_OK);
		return false;
	}
	duilibBaseWnd.CenterWindow();
	duilibBaseWnd.ShowWindow(SW_SHOW);

	//Duilib消息循环
	CPaintManagerUI::MessageLoop();
	::CoUninitialize();

	return 0;
}
所以,从上面我们自定义和实现支持Duilib特性窗体我们可以看出,主要重写窗口过程函数接收窗口消息处理,在创建窗体时,解析XML,Duilib接管窗口句柄和根UI元素节点,消息流向Duilib消息处理等一系列操作,设置资源路径就可以实现一个支持Duilib XML描述和渲染窗体的特性!
  1. 接收Duilib事件消息
//继承INotifyUI类,重写Notify接口
class CBaseDuilibWnd :public CWindowWnd,public INotifyUI
virtual void Notify(TNotifyUI& msg);
void CBaseDuilibWnd::Notify(TNotifyUI& msg)
{
	if (msg.sType == TEXT("windowinit"))
	{
		OnInitWindow();
	}
	else if (msg.sType == TEXT("click"))
	{
		CDuiString strName = msg.pSender->GetName();
		strName += L" click";
		MessageBox(NULL, strName, L"Info", NULL);
	}
}
//在窗体创建时(WM_CREATE)将当前窗体对象加入到Duilib事件通知里
m_pmUI.AddNotifier(this);

总结:通过上述流程,我们就可以掌握纯粹利用Duilib创建Win32窗体,Duilib特性窗体!

作者: 祁莫问.

下一篇: 二.Duilib开发之消息系统.

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值