C++图形界面库之Duilib

该文章已生成可运行项目,

一、 Duilib 是什么?

Duilib 是一个强大的、开源的 Windows 平台下的 DirectUI 界面库。

Duilib 是一个让你能用 C++ 和 XML 文件来高效开发出漂亮、自定义程度高的 Windows 桌面客户端软件的开发框架。​

二、 核心特点与优势

极高的界面定制能力​: 由于所有控件都是自绘的,开发者可以完全控制控件的外观,轻松实现各种炫酷、个性化的界面效果(如换肤、不规则窗口、动画等),彻底摆脱 Windows 原生控件呆板的样式。

分离界面与逻辑​: 这是 Duilib 最大的优点之一。通过 XML 文件定义界面布局和样式(类似于 HTML),C++ 代码处理业务逻辑。这使得UI设计师和程序员可以并行工作,后期修改界面也无需重新编译C++代码,只需更新 XML 和资源文件即可,大大提升了开发效率和可维护性。

轻量级、高性能​: 库本身非常精简(核心库几百KB),不依赖像 MFC、.NET Framework 这样的大型框架。直接基于 Windows API 和 GDI/GDI+,启动速度快,内存占用小。

开源免费​: Duilib 遵循 BSD 开源协议,可以免费用于商业项目,这在当年是吸引大量开发者的一个重要原因。

​丰富的控件库​: 提供了大量常用的控件,如按钮、标签、列表框、树形控件、选项卡、进度条等,并且支持控件的自定义扩展。

三、 架构与工作原理

1. 核心架构

一个典型的 Duilib 程序包含以下几个核心部分:

XML 界面文件​: 描述窗口的层次结构、控件属性、样式(位置、大小、颜色、图片、字体等)。它支持类似 CSS 的 class和 id选择器,可以实现样式的复用。

资源文件​: 图片、图标等资源。

​程序框架​:

​窗口类​: 继承自 WindowImplBase或类似的基类,负责消息处理、控件事件响应。

​控件管理器​: 管理所有控件的创建、查找、消息分发。

渲染引擎​: 负责将 XML 描述和资源文件最终绘制到屏幕上。

​消息循环​: 封装了 Windows 的消息泵。

2. 基本工作流程

程序启动​: 进入 WinMain函数,初始化 Duilib 环境。

​创建窗口​:

程序创建一个继承自 WindowImplBase的类(如 CMainWnd)。

在该类中指定其关联的 XML 文件路径(如 _tcsdup(_T(“main.xml”)))。

解析 XML​: Duilib 引擎读取并解析 XML 文件,根据描述递归地创建出所有控件对象,并建立起控件树。

​消息循环​: 程序进入主消息循环。Duilib 会拦截 Windows 消息(如 WM_PAINT, WM_MOUSEMOVE等)。

消息映射与事件处理​

Duilib 将 Windows 消息转换为更易处理的事件(如 click, select等),并分发给相应的控件。

程序员在窗口类中通过消息映射宏​(如 DUILIB_BEGIN_MSG_MAP)来响应这些事件。

绘制​: 当需要重绘时(如收到 WM_PAINT消息),Duilib 会遍历控件树,调用每个控件的 DoPaint方法,使用 GDI/GDI+ 将控件绘制到窗口上。

四、 一个简单的代码示例

// DuiLibTest.cpp : 定义应用程序的入口点。
// 首先创建一个MFC项目,然后将Duilib的UIlib头文件加载添加入项目中
// 然后将编译好的DuiLib.lib链接到项目
#include "stdafx.h"
#include "DuiLibTest.h"
#include "UIlib.h"

using namespace DuiLib;

// 窗口实例及消息响应部分
class CFrameWindowWnd : public CWindowWnd, public INotifyUI
{
public:
	CFrameWindowWnd() { };
	LPCTSTR GetWindowClassName() const { return _T("UIMainFrame"); };
	UINT GetClassStyle() const { return UI_CLASSSTYLE_FRAME | CS_DBLCLKS; };
	void OnFinalMessage(HWND /*hWnd*/) { delete this; };

	void Notify(TNotifyUI& msg)
	{
		if (msg.sType == _T("click")) {
			if (msg.pSender->GetName() == _T("closebtn")) {
				Close();
			}
		}
	}
	LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		if (uMsg == WM_CREATE) {
			m_pm.Init(m_hWnd);
			CDialogBuilder builder;
			CControlUI* pRoot = builder.Create(_T("test1.xml"), (UINT)0, NULL, &m_pm);
			ASSERT(pRoot && "Failed to parse XML");
			m_pm.AttachDialog(pRoot);
			m_pm.AddNotifier(this);
			return 0;
		}
		else if (uMsg == WM_DESTROY) {
			::PostQuitMessage(0);
		}
		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;
		if (m_pm.MessageHandler(uMsg, wParam, lParam, lRes)) return lRes;
		return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
	}

public:
	CPaintManagerUI m_pm;
};

// 程序入口及Duilib初始化部分
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow)
{
	CPaintManagerUI::SetInstance(hInstance);
	CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath());

	CFrameWindowWnd* pFrame = new CFrameWindowWnd();
	if (pFrame == NULL) return 0;
	pFrame->Create(NULL, _T("测试"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
	pFrame->ShowWindow(true);
	CPaintManagerUI::MessageLoop();

	return 0;
}

详情可见Duilib源码文件中doc文件中的文档
在这里插入图片描述
在这里插入图片描述

Duilib 在国内拥有大量用户,尤其流行于

​腾讯​: 众多软件如 PC 版 QQ、QQ音乐、腾讯视频等都曾使用或参考过 Duilib 或其思想。
许多中小型公司的桌面客户端,特别是对界面美观度要求较高的产品,如各种播放器、下载器、直播助手、游戏辅助工具等。

Duilib 是 Windows C++ 客户端开发历史上一个里程碑式的界面库。它以其强大的自定义能力、清晰的界面逻辑分离和轻量级的特性,在需要高度定制UI的桌面应用开发中占据了重要一席之地。尽管在今天,Qt、Electron 等跨平台框架更为流行,但对于追求极致性能、小巧体积和 Windows 原生体验的项目来说,Duilib 依然是一个非常优秀和值得考虑的选择。

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值