布局与绘制
- 控件布局:靠上、靠下、靠左、靠右、居中、相对、绝对
- 尺寸:固定宽高、最大最小宽高、按文本或子控件自动调整
- 背景:无锯齿颜色、图片、圆角、渐变,以及自定义 Bitmap
- SVG图片:覆盖比常见看图工具和部分开源库更全的格式
- DPI:切换一行代码完成,设计器里可预览各 DPI 效果
- RichText:同一段文字分字体、分颜色,支持多行与六向对齐
- Clone:复制出相同控件;Attach / Detach 随意挂到父节点
X,不被定义,无限可能。
前身DUIThink。
XUI是带可视化设计器的跨平台界面开发框架。
它可以像 MFC 一样自动生成窗体类、控件变量和消息映射,并带上线程池、文件、网络、监听等常用开发部件,用来直接做应用。
它可根据设计图直接生成ui。
开源 · C++ · 跨平台
XUI 更接近一套开发框架。线程池、文件操作、网络模型、文件监听、注册表监听、文件拖拽、命令行解析、磁吸算法、内存池、分辨率转换、字符串操作这些部件和界面库在同一套框架里,可以直接用来做完整应用。 设计器负责把界面做成看得见、改得动的结果,避免手写界面时记属性、来回预览。
控件演示和已经用这套界面做出来的应用。
从设计界面到生成代码的操作演示。
更多教程: bilibili 空间
C++ Demo · Release
DemoWindows.zip · 5.4 MB
下载 Windows DemoWindows Demo 用 Visual Studio 直接编 Win32 版,不需要 SDL3。开关在 MMHelper/DuiPlatformSDL.props,DuiPlatformSDL 保持默认的 false,也就是不定义 DuiPlatform_SDL。只有改成 true 才会走 SDL3。
用 Visual Studio 打开 XUI.2017.sln,配置选 Release_Unicode | Win32,先编出库。DLL 会拷到仓库的 bin 目录(XUI.2017.dll、MMHelper.2017.dll)。
再打开 Demo\XUIDemo_C++\XUIDemo_C++.sln,配置选 Release | Win32。工程会把这两个 DLL 拷到 Demo\XUIDemo_C++\Release,并生成 XUIDemo_C++.exe。
程序从可执行文件的上一级打开 ../XUIDemo_C++.DuiProj/XUIDemo_C++.DuiProj。把 Release 目录(XUIDemo_C++.exe、XUI.2017.dll、MMHelper.2017.dll)和它旁边的 XUIDemo_C++.DuiProj 按这个相对位置打进 zip,就是 DemoWindows.zip。
C++ Demo · WSL
DemoLinux.tgz · 8.2 MB
下载 Linux DemoLinux 包是在 WSL 里编译的,源码直接用 Windows 盘上的仓库,不另拷一份。G: 在 WSL 里是 /mnt/g。先安装编译器、CMake、Ninja 和 SDL3 开发包。
sudo apt install cmake ninja-build g++ libsdl3-dev cmake -S /mnt/g/Project/DirectUI/DUIThink-Develop -B ~/build-xui -G Ninja \ -DCMAKE_BUILD_TYPE=Release -DXUI_PLATFORM_SDL=ON cmake --build ~/build-xui --target XUI XUIDemo_C++ -j
产物在 ~/build-xui/Debug:XUIDemo_C++、libXUI.so。再把 libSDL3.so 和中文字体 wqy-microhei.ttc 放到同一目录。工程目录 Demo/XUIDemo_C++/XUIDemo_C++.DuiProj 要作为 Debug 的上一级,因为程序读的是 ../XUIDemo_C++.DuiProj/XUIDemo_C++.DuiProj。把这一层打成 tar.gz,就是 DemoLinux.tgz。仓库里的 pack-vm.sh 是同一套打包,路径和目标名要以当前 CMake 为准。
C++ Demo · Release
DemoMac.zip · 5.5 MB
下载 macOS Demo在 Mac 上安装 SDL3 和 CMake,然后在仓库根目录编译。CMake 会生成 XUIDemo_C++.app,并把 libXUI.dylib、SDL3 拷进 App,同时把 DuiProj 链到 Debug 的上一级。
brew install sdl3 cmake ninja cmake -S . -B build-macos -G Ninja -DCMAKE_BUILD_TYPE=Release -DXUI_PLATFORM_SDL=ON cmake --build build-macos --target XUI XUIDemo_C++
把 build-macos/Debug 里的 XUIDemo_C++.app,连同它上一级的 XUIDemo_C++.DuiProj 目录一起打成 zip,就是 DemoMac.zip。App 的 rpath 是 @executable_path,库必须留在 App 里面。
arm64-v8a · APK
DemoAndroid.apk · 10.5 MB
下载 Android DemoAndroid 也在 WSL 里打,工程就是 G:\Project\DirectUI\DUIThink-Develop(WSL 路径 /mnt/g/Project/DirectUI/DUIThink-Develop)。需要 JDK 17、Android SDK(platform android-35、build-tools 35.0.0、NDK 27.2.12479018、CMake 3.22.1),以及 app/libs 里的 SDL3-3.4.16.aar。
cd /mnt/g/Project/DirectUI/DUIThink-Develop/Android/DUIThinkDemo echo "sdk.dir=$ANDROID_HOME" > local.properties chmod +x ./gradlew ./gradlew --no-daemon assembleRelease
编译前 Gradle 会把 Demo/XUIDemo_C++/XUIDemo_C++.DuiProj 拷进 assets。native 由仓库根目录的 CMakeLists 编出 arm64-v8a 的 libmain.so。APK 在 app/build/outputs/apk/release/app-release.apk,拷出来就是 DemoAndroid.apk。调试包可以把最后一行换成 assembleDebug,或按同样路径跑仓库里的 pack-android.sh。
XUI 是带可视化设计器的跨平台界面框架,前身是 DUIThink。X 的意思是不被定义,无限可能。许可证是 LGPL-2.1。它把界面和业务拆开:界面放在 .DuiProj 工程里,行为用接近 MFC 的窗体类、控件变量和消息映射来写。
控件没有自己的窗口句柄。整棵控件树挂在一个窗口上,由框架做命中测试、布局和绘制。Windows 默认走 Win32;Linux、macOS、Android 走 SDL3。
源码仓库是 github.com/miaomiaoyule/XUI。下面按这棵目录读,点左侧条目进入对应说明。
MFC 做复杂皮肤时,很多地方要自己画,改样式成本高。纯手写 XML 又没有预览,属性名也不好记。XUI 把这两件事分开:
.DuiProj 里,由设计器维护。所以它既是界面库,也带一套可以直接拿来写程序的部件:线程池、文件、网络、监听、拖拽、命令行、磁吸、DPI、字符串。这些在 里,不依赖控件树。
仓库按库、工具、示例和预编译库分开。应用工程通常同时依赖 XUI 和 MMHelper。头文件入口是 XUI/XUIHead.h,它会继续包含 MMHelper/MMHelperHead.h。
| 路径 | 作用 |
|---|---|
XUI/ | 界面框架。导出窗口、控件、资源、工厂 |
XUI/DUIControl/ | 具体控件 |
XUI/DUICore/ | 窗口、绘制、消息泵、动画 |
XUI/DUIManager/ | CDUIGlobal、CDUIFactory |
XUI/DUIXmlPack/ | 读写 DuiProj |
MMHelper/ | 与界面解耦的基础库 |
ThirdDepend/ | tinyxml2、libwebp、SVG |
lib/ | 按 VS 版本、Win32/x64、Debug/Release、MD/MT 区分的预编译库 |
Demo/XUIDemo_C++/ | 主示例:控件、DPI、换肤、SVG、聊天界面 |
Demo/FlowSheet/、Demo/Scratch/ | 较小示例 |
XUI.2017.sln | 库工程 |
XUI.2017.Design.sln | 带设计器宏的库工程 |
上层只使用下层暴露的类和宏。XML 和绘制细节留在框架内部。
应用窗体(继承 CDUIWnd / CDUINotifyPump)
|
消息映射、控件查找、业务通知
|
CDUIWnd:窗口、焦点、捕获、绘制表面、定时器
|
控件树:CDUIControlBase 及其子类
|
属性 CDUIPropertyObject + CDUIAttribute*
资源:字体 / 颜色 / 图片
|
CDUIGlobal + CDUIFactory + CDUIXmlPack
|
MMHelper + 绘制后端(Win32 为 GDI/GDI+,SDL 平台为 SDL)
| 层 | 关键类型 | 职责 |
|---|---|---|
| 应用 | CDlgDemo | 创建窗口、绑定控件、响应点击和定时器 |
| 窗口 | CDUIWnd | 持有窗口,分发输入,管理根控件 |
| 控件 | CDUIControlBase | 位置、可见性、背景、命中、克隆 |
| 属性 | CDUIAttribute* | 设计器和 XML 都能读写的字段 |
| 全局 | CDUIGlobal | 加载工程、资源表、DPI、换肤 |
| 工厂 | CDUIFactory | 按 XML 类名创建控件、资源和属性 |
| 序列化 | CDUIXmlPack | 读写工程、皮肤、字体、颜色、界面 XML |
窗口实现按平台分开:DUIWndWin32 和 DUIWndSDL,对外仍是 CDUIWnd。
导出宏在 XUIHead.h:
| 宏 | 谁定义 | 效果 |
|---|---|---|
XUISDK | 编译 XUI DLL 的工程 | 符号 dllexport |
XUILIB | 静态链接 XUI 的工程 | 不使用 dllimport,并让 MMHelper 也按静态库处理 |
| 两者都不定义 | 普通应用 | 按 DLL 导入使用 |
MMHelper 使用同一套约定:MMHELPER_DLL / MMHELPLIB。
开关在 MMHelper/DuiPlatformSDL.props。属性 DuiPlatformSDL 默认是 false,也就是不定义 DuiPlatform_SDL,走 Win32,不需要 SDL3。改成 true 才会定义 DuiPlatform_SDL 并链接 SDL3。
Linux、macOS、Android 用 CMake,选项 XUI_PLATFORM_SDL 打开后同样定义 DuiPlatform_SDL。这三端需要 SDL3。Windows 上发布 Demo 用的是 Visual Studio 的 Win32 配置,见 。
主示例 Demo/XUIDemo_C++/XUIDemo_C++/XUIDemo_C++.cpp 就是最小闭环。桌面端入口如下:
CDUIGlobal::GetInstance()->Init(hInstance);
CDUIGlobal::GetInstance()->LoadProjectFromFile(
_T("../XUIDemo_C++.DuiProj/XUIDemo_C++.DuiProj"));
CMMDpi::SetProcessDPIAwareness(
enMMPROCESS_DPI_AWARENESS::MMPROCESS_PER_MONITOR_DPI_AWARE);
CDlgDemo DlgDemo;
DlgDemo.Create(NULL, _T("XUIDemo"), DUI_WNDSTYLE_FRAME, DUI_WNDSTYLE_EX_FRAME);
DlgDemo.DoModal();
CDUIGlobal::GetInstance()->UnInit();
Init 保存实例,准备绘制、线程池和 DPI。LoadProjectFromFile 读入整个 UI 工程:皮肤、字体、颜色、属性表、控件 ID、各个界面 XML。CDlgDemo 构造时把界面名设为 "DlgMain"。这个名字对应工程里的一条界面记录。Create 创建窗口,按界面名把 XML 实例化成控件树。DoModal 进入模态消息循环。DoBlock 是另一种阻塞循环,Demo 的 DPI 窗口用的就是它。UnInit 关闭工程并释放全局资源。工程也可以不放在磁盘目录里:
| 接口 | 场景 |
|---|---|
LoadProjectFromFile | 开发期,直接读 .DuiProj 目录 |
LoadProjectFromZip | 从 zip 文件或内存加载,可带密码 |
LoadProjectFromResZip | 把 zip 打进程序资源,类型默认 "ZIP" |
加载失败时用 GetDuiLastError() 取最后一条错误文本。Android 上 Demo 会先把 assets 里的 DuiProj 拷到内部存储,再调用 LoadProjectFromFile。程序从可执行文件的上一级打开 ../XUIDemo_C++.DuiProj/XUIDemo_C++.DuiProj。
CDUIWnd 同时是可设计对象、动画窗口和通知泵。它上面维护根控件、捕获、焦点、悬停、按控件 ID 索引的表、单选分组、绘制表面、Tooltip、插入符和定时器。
| 方法 | 用途 |
|---|---|
Create | 创建顶层或子窗口 |
DoModal / DoBlock | 阻塞消息循环 |
ShowWindow / Close / CenterWindow | 显示、关闭、居中 |
FindControl | 按 ID 或回调在整棵树上找控件 |
SetDpi / SetScale | 当前窗口的 DPI 或百分比缩放 |
AddINotify / RemoveINotify | 让外部对象接收本窗口通知 |
SetCapture / SetFocusControl | 捕获与焦点 |
样式宏在 DUIExport/DefineBase.h:
DUI_WNDSTYLE_FRAME:重叠窗口DUI_WNDSTYLE_DIALOG:弹出对话框DUI_WNDSTYLE_CHILD:子窗口DUI_WNDSTYLE_EX_FRAME / DUI_WNDSTYLE_EX_DIALOG:对应扩展样式标题栏、关闭按钮、圆角背景由 XML 里的控件自己画。系统样式只决定窗口种类。未进入消息映射的窗口消息可以重写 OnWndMessage。Demo 用它接收托盘消息和 DPI 窗口句柄。
输入先进入 CDUIWnd。框架做命中测试后,把鼠标、键盘、定时器转换成 DuiNotify,再交给 CDUINotifyPump。映射宏在 DUIExport/DefineMessage.h。
DuiBegin_Message_Map(CDlgDemo, CDUIWnd)
Dui_On_Notify_Ctrl(DuiNotify_Timer, IDC_TabViewControls, OnTimerTabViewControls)
DuiEnd_Message_Map()
| 宏 | 含义 |
|---|---|
DuiDeclare_Message_Map() | 在类里声明映射表 |
DuiBegin_Message_Map(类, 基类) | 开始映射,并链接基类表 |
Dui_On_Click_Ctrl(控件ID, 函数) | 指定控件的点击 |
Dui_On_SelectChanged_Ctrl | 选中状态变化 |
Dui_On_Notify_Ctrl(通知, 控件ID, 函数) | 任意通知加控件 ID |
Dui_On_Notify(通知, 函数) | 不限控件 ID |
Dui_On_Timer() | 定时器,处理函数固定为 OnDuiTimer |
Dui_On_KillFocus_Ctrl | 失去焦点 |
处理函数签名统一为 void Member(const DuiNotify &Notify)。Notify.wParam、Notify.lParam、Notify.pNotifyCtrl 携带上下文。定时器 ID 在 wParam 里。
常见通知:DuiNotify_WndInited、DuiNotify_WndLayout、DuiNotify_DpiChanged、DuiNotify_Click、DuiNotify_TextChanged、DuiNotify_SelectChanged、DuiNotify_ItemClick、DuiNotify_WndManagerAttach、DuiNotify_WndManagerDetach。
设计器为每个控件生成数字 ID,写在工程的 ResourceCtrlID.h。窗体类在 OnFindControl 里用 Dui_DDX_Control 绑定成员。这个宏会 FindControl 并做接口查询。
void CDlgDemo::OnFindControl()
{
__super::OnFindControl();
Dui_DDX_Control(CDUIContainerCtrl, m_pTabViewControls, IDC_TabViewControls)
Dui_DDX_Control(CDUIRadioBoxCtrl, m_pRadioViewHomePageCtrl, IDC_RadioBoxHomePage)
}
OnInitDialog 适合做创建后的一次性逻辑:把子页面挂到逻辑类、创建托盘、居中、设置默认选中项。
大窗口不要把所有逻辑堆在一个对话框类里。Demo 的做法是:
TabLayout 或 VerticalLayout 划出一块容器。CDUINotifyPump 的视图类。OnInitDialog 里 FindSubControl 找到这块容器,调用视图类的 Attach。Attach 内部 GetWndOwner()->AddINotify(this),同一套消息映射就可以写在视图类里。析构时要 RemoveINotify,避免窗口还在派发通知。
所有可视对象都从 CDUIControlBase 派生,而它又是 CDUIPropertyObject。类名同时是 XML 节点名,工厂按这个字符串创建对象。
CDUIPropertyObject
└── CDUIControlBase
├── CDUIStaticCtrl / CDUIButtonCtrl / CDUIEditCtrl / ...
└── CDUIContainerCtrl
├── CDUIHorizontalLayoutCtrl / CDUIVerticalLayoutCtrl
├── CDUITabLayoutCtrl
├── CDUIListViewCtrl / CDUITreeViewCtrl
└── CDUIGroupCtrl / ...
| 类名 | 说明 |
|---|---|
CDUIStaticCtrl | 文本、富文本,可按文本自动算宽高 |
CDUIButtonCtrl | 按钮,普通、悬停、按下、禁用图 |
CDUICheckBoxCtrl / CDUIRadioBoxCtrl | 复选、单选。单选按组互斥 |
CDUIEditCtrl | 自绘编辑框,可插入图片和动图 |
CDUIRichEditCtrl | 富文本编辑 |
CDUIProgressCtrl / CDUISliderCtrl | 进度、滑块 |
CDUIHorizontalLayoutCtrl / CDUIVerticalLayoutCtrl | 水平、垂直布局 |
CDUITabLayoutCtrl | 分页容器 |
CDUIListViewCtrl | 列表。List、TileH、TileV 之间切换,子项可拖动换位 |
CDUITreeViewCtrl | 树。选中按钮、表头、单选靠属性切换 |
CDUIComboxCtrl | 下拉框,支持子项梯度滑动 |
CDUIMenuCtrl / CDUIRotateMenuCtrl | 多级菜单、3D 旋转菜单 |
CDUIAnimateCtrl / CDUIWaterCtrl | GIF、序列帧、水波纹 |
CDUICalendarCtrl / CDUIClockCtrl / CDUIDateTimeCtrl | 日历、时钟、日期时间 |
CDUIIPAddressCtrl / CDUIHotKeyCtrl | IP 地址、热键 |
每个控件都有背景色、渐变、背景图、圆角、边框、自定义 Bitmap、Clone 和 SetParent。静态文本用 SetAutoCalcWidth / SetAutoCalcHeight 按文字收缩。容器用同名接口按子控件收缩。
位置由 CDUIAttributePosition 描述。每个控件相对父容器声明水平和垂直对齐,再加偏移、固定宽高和最小最大尺寸。
| 方向 | 取值 | 含义 |
|---|---|---|
| 水平 | HorizAlign_Left / Right / Center | 靠左、靠右、水平居中 |
| 垂直 | VertAlign_Top / Bottom / Middle | 靠上、靠下、垂直居中 |
SetFloat 让控件脱离自动流,再用 SetAbsoluteRect 按绝对矩形摆放。父容器排布时调用 GetAbsoluteRect 得到子控件矩形。DPI 变化后,内边距可以选择是否跟随缩放。
列表视图类型是:
enum enDuiListViewType
{
ListView_List,
ListView_TileH,
ListView_TileV,
};
调用 CDUIListViewCtrl::SwitchListViewType 切换。网格效果由平铺模式和项尺寸组合出来。
设计器和 XML 能编辑的字段,都是 CDUIAttributeObject 的子类,挂在 CDUIPropertyObject 的属性组里。
| 属性类 | 存什么 |
|---|---|
CDUIAttributeBool / Long / Float | 标量 |
CDUIAttributeText / TextStyle / RichText | 文本、对齐、分段富文本 |
CDUIAttributeColor / ColorSwitch | 单色,或一组可切换的颜色资源名 |
CDUIAttriImageSection | 图片、九宫格、源矩形、平铺 |
CDUIAttributePosition / Size / Rect | 布局与矩形 |
CDUIAttributeDuiSelect / TabSelect / CtrlID | 引用另一份界面、当前页、控件 ID |
属性值多数不直接写死在控件 XML 里,而是存一个 ValueID。真正的值在工程级 Attribute.xml 中按哈希去重。多个控件可以共享同一套圆角、字体或颜色,改一处即可作用于全部引用。
富文本允许一段文字拆成不同字体和颜色,并支持多行以及左、右、上、下、居中对齐。
CDUIGlobal 启动后维护三张表:字体 CDUIFontBase、颜色 CDUIColorBase、图片 CDUIImageBase。图片包括 PNG、JPEG、GIF、WebP、SVG。绘制支持九宫格、圆角和平铺。
颜色和图片属性可以保存一组资源名。PerformSwitchRes(nIndex) 切换当前皮肤序号,GetSwitchResIndex 读取当前序号。ColorSwitch 按这个序号取对应颜色。Demo 里的写法:
int nSkin = (CDUIGlobal::GetInstance()->GetSwitchResIndex() + 1) % 2;
CDUIGlobal::GetInstance()->PerformSwitchRes(nSkin);
换肤索引是全局的。一个进程里已加载的界面共享这个序号。资源增删改可以通过 IDuiResourceCallBack 观察。
进程级用 CMMDpi::SetProcessDPIAwareness,Demo 使用 Per-Monitor。界面级用 CDUIGlobal::SetDpi / SetScale,以及窗口自己的同名方法。SetScale(100) 表示 100%,内部按 96 DPI 换算。全局 SetDpi 会同步已经打开的窗口。只想缩放某一个窗口时,调用该 CDUIWnd 自己的 SetDpi / SetScale。
CDUIWnd 维护一张后台位图。控件的 OnPaint 在裁剪区内把背景、边框、文字和前景画上去,再贴到窗口。分层透明由窗口属性 WndLayered 和 WndAlpha 控制。Win32 下 GdiplusRenderText、GdiplusRenderImage 决定文字和图片走 GDI 还是 GDI+。
动画分三处:
CDUIAnimation::StartAnimation:通用帧动画,回调开始、步进和结束。水波纹数据挂在控件的涟漪位图上,由 CDUIWaterCtrl 和基类配合完成。
一个界面工程是一个目录,入口文件扩展名是 .DuiProj。Demo 的入口是 XUIDemo_C++.DuiProj,内容是资源索引:
<Version Version="5"/>
<SkinRes SkinFile="SkinRes.xml"/>
<FontRes FontFile="FontRes.xml" Default="微软雅黑-字号:12-..."/>
<ColorRes ColorFile="ColorRes.xml"/>
<Attribute AttributeFile="Attribute.xml"/>
<ResourceCtrlID CtrlIDFile="ResourceCtrlID.h"/>
<DirectUI DuiName="DlgMain" DuiType="0" DuiFile="Dlg/DlgMain.xml"/>
| DuiType | 用途 |
|---|---|
| 0 对话框 | 独立窗口。构造 CDUIWnd 时使用这个名字 |
| 1 视图 | 可嵌入的视图片段 |
| 2 列表项模板 | 运行时 Clone 成每一行 |
| 3 树节点模板 | 树节点 |
| 4 菜单 / 5 三维菜单 / 6 日历 | 弹出层 |
界面 XML 的根是窗口类名,子节点是控件类名。属性节点带 NameID、ValueID 或内联 Value。日常用设计器改界面,它会同时维护 XML、Attribute.xml 和 ResourceCtrlID.h。
运行时动态插入一块界面:
CDUIControlBase *pCtrl = CDUIGlobal::GetInstance()->LoadDui(_T("ComboxView1"), pWnd);
列表项模板应 Clone 后再插入,这样每一行是独立实例。Clone 默认会刷新控件 ID。若要保持原 ID,把刷新参数设为 false。
CDUIFactory 按类名字符串创建控件、资源和属性。XML 解析到 <CDUIButtonCtrl> 时,工厂调用对应的创建函数。
CDUIControlBase 或某个布局控件。DuiDeclare_CreateControl(CMyCtrl)。DuiImplement_CreateControl(CMyCtrl),并在 InitProperty 里注册自己的属性组。DuiRegisterCreateControl(CMyCtrl)。设计器要识别自定义控件,需要在带设计器宏的库工程里提供控件描述。普通应用工程不必定义这个宏。XML 节点名必须和注册的类名一致,否则创建失败,整段子树加载不出来。
IDuiControlCallBack 用来在不改控件类的情况下监听绘制、尺寸、可见性和释放。
MMHelper 不依赖控件树。XUI 和普通 Win32 程序都能用。CDUIGlobal 自己持有线程池,界面线程和后台任务可以通过服务消息通信。
| 模块 | 类型 | 用途 |
|---|---|---|
| 字符串 | CMMString | 统一字符串 |
| 文件 | CMMFile | 路径和读写 |
| 线程 | CMMThreadPool、CMMService | 线程池和服务消息 |
| 网络 | MMTCPSocketClient、MMTCPSocketServer | TCP |
| 监听 | MMFileMonitor、MMRegMonitor | 目录变化、注册表变化 |
| 拖放 | CMMDragDrop | OLE 拖放 |
| DPI | CMMDpi | 感知级别和缩放换算 |
| 其他 | CMMCommandLine、CMMTrayIcon、MMMagnetBox、MMSvg | 命令行、托盘、磁吸停靠、SVG |
Demo 里的托盘使用 CMMTrayIcon,鼠标消息以自定义窗口消息回到 OnWndMessage。命令行使用 CMMCommandLine,用来区分主 Demo 和 DPI 预览进程。
用 Visual Studio 打开 XUI.2017.sln,配置选 Release_Unicode | Win32,先编出库。DLL 会拷到仓库的 bin(XUI.2017.dll、MMHelper.2017.dll)。保持 DuiPlatformSDL 为 false,这一端不需要 SDL3。
再打开 Demo/XUIDemo_C++/XUIDemo_C++.sln,配置选 Release | Win32,确认示例能跑起来。新工程照它的包含目录和库目录来:包含 XUIHead.h,运行目录能找到对应 DLL。字符集使用 Unicode。头文件里已经写了公共控件 6.0 的 manifest。
这三端打开 XUI_PLATFORM_SDL,需要 SDL3。Linux 在 WSL 里直接编译本机仓库,macOS 用 CMake 生成 App,Android 用 Gradle 打 APK。各端命令和打包步骤在 平台 Demo。
class CMainWnd : public CDUIWnd
{
DuiDeclare_Message_Map()
public:
CMainWnd() : CDUIWnd(_T("DlgMain")) {}
protected:
CDUIButtonCtrl *m_pClose = NULL;
void OnFindControl() override
{
__super::OnFindControl();
Dui_DDX_Control(CDUIButtonCtrl, m_pClose, IDC_BtnClose)
}
void OnClickClose(const DuiNotify &)
{
Close(IDOK);
}
};
DuiBegin_Message_Map(CMainWnd, CDUIWnd)
Dui_On_Click_Ctrl(IDC_BtnClose, OnClickClose)
DuiEnd_Message_Map()
IDC_BtnClose 必须来自设计器生成的 ResourceCtrlID.h,并且 XML 里该按钮的 ID 与宏一致。入口顺序与 相同。
开发时用目录形式的 .DuiProj,方便设计器来回保存。发布可以:
LoadProjectFromFile。可执行文件在 Release/ 里时,DuiProj 目录要放在它的上一级。LoadProjectFromZip。LoadProjectFromResZip。图片文件在 SkinRes/。SkinRes.xml 只记录资源名到文件名的映射。
设计器单独提供,绑定 Visual Studio 的解决方案后可以:
手写 XML 可以跑通框架,但属性哈希和控件 ID 很容易和 Attribute.xml、ResourceCtrlID.h 对不上。新界面在设计器里做,C++ 只处理绑定之后的行为。设计器安装包在页面顶部的「下载设计器」。
读 Demo/XUIDemo_C++ 时,先看 .DuiProj 里的 DuiName,再在 C++ 里搜同名构造,就能把 XML 和类对上。
| 路径 | 说明 |
|---|---|
XUIDemo_C++.cpp | 初始化、加载工程、命令行分流、模态主窗口 |
DlgDemo.cpp | 主窗口绑定、子视图 Attach、托盘定时器 |
BaseControl/ | 静态文本、复选、单选、进度、组合框 |
Usage/DpiDlg | 拉起 DPI 预览,滑块改变缩放 |
Usage/SwitchSkin | 换肤入口 |
Usage/SvgImage | SVG 资源 |
QQ/ | 聊天窗、表情、列表项模板 |
Demo/FlowSheet 是流程类小示例。Demo/Scratch 是更小的启动样例。
delete 正在派发事件的控件。FindControl 依赖 InitControls 建立的 ID 表。动态插入后要让控件进入当前窗口。CDUINotifyPump 派生类的成员,控件 ID 用编译期常量。SetScale。| 熟悉的概念 | 在 XUI 里 |
|---|---|
MFC CDialog | CDUIWnd 子类 + 一个对话框界面 |
| DDX | OnFindControl + Dui_DDX_Control |
| 消息映射 | DuiBegin_Message_Map / Dui_On_Click_Ctrl |
| 对话框资源 | .DuiProj + Dlg/*.xml |
| 控件 ID | ResourceCtrlID.h 里的 IDC_* |
接口和示例以仓库为准。使用问题进 QQ 群。