一、 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 依然是一个非常优秀和值得考虑的选择。
928

被折叠的 条评论
为什么被折叠?



