GuiLite 中文技术指南:4 千行全平台纯头文件 GUI 库的架构、构建与实战
GuiLite 中文技术指南:4 千行全平台纯头文件 GUI 库的架构、构建与实战
导读:本文以 GuiLite 的中文说明文档(README_zh.md)为主线,系统讲解这一"大道至简"的纯头文件 GUI 库——为什么它能以 4 千行 C++ 代码同时运行在单片机与智能手机上、如何把它集成进你的应用、以及它的图层渲染与消息传递架构是如何设计的。读完本文,你将掌握 GuiLite 的构建命令、集成方式、核心类接口,并理解其"界面元素管理 + 图形绘制"两大核心机制,可直接上手 HelloXXX 系列示例或开发自己的 GUI 框架。
项目定位:轻·快·容
GuiLite 对自己的定位可以用三个字概括:轻(Lightweight)、快(Fast)、容(Compatible),这也是 README_zh.md 中开篇的核心主张:
- 轻量:约 4 千行 C++ 代码,零依赖,是单一头文件库(
GuiLite.h)。整个仓库的源码被组织在 src/core 与 src/widgets 两个目录下,最终通过脚本合并成一个头文件。 - 超快:高效的渲染实现,官方文档声称在单片机(MCU)上也能流畅运行。渲染路径是"像素级"的——从 display.h 可以看到
draw_pixel/fill_rect/flush_screen直接面向物理 framebuffer 操作,没有中间层开销。 - 兼容:可与第三方 GUI 框架(Qt / MFC / Winform / Cocoa / Web)共存运行,现有 Qt/MFC 代码可以继续使用,GuiLite 只负责自己擅长的绘制与控件部分。
最低硬件要求
官方文档给出了明确的最低硬件门槛,这也是判断"这个库适不适合我的板子"最直接的参考:
| Processor(处理器) | Disk/ROM space(存储) | Memory(内存) |
|---|---|---|
| 24 MHz | 29 KB | 9 KB |
这意味着 29 KB 的 ROM/Flash 与 9 KB 的 RAM 即可跑起一套完整 GUI——这正是它面向 STM32 等 MCU 场景的底气所在。从源码结构看,这一极低开销来源于两层设计:
- 纯头文件、零依赖:不依赖标准图形库、字体库或操作系统 GUI 子系统;
- 渲染直达显存:
c_surface的底层绘制函数(draw_pixel_low_level、fill_rect_low_level)直接写 surface 的 framebuffer,且只在需要时通过flush_screen一次性同步到物理显存。
上图来自仓库 documents/WhyGuiLite-cn.png,直观展示了 GuiLite 相比传统 GUI 方案在代码规模、硬件门槛上的差异定位(图片内容以仓库实际文件为准)。
跨平台能力矩阵
README_zh.md 从三个维度描述了 GuiLite 的跨平台能力:
支持的操作系统:
- iOS / macOS / WatchOS
- Android
- Linux(ARM / x86-64)
- Windows(包含 VR / Mixed Reality 场景)
- RTOS(实时操作系统)
- 甚至无操作系统的单片机
支持的开发语言:C/C++、Swift、Java、Javascript、C#、Golang……
支持的第 3 方库:Qt、MFC、Winforms、CoCoa……
这一能力的实现关键在 adapter 适配层。仓库 src/core/adapter 下按平台隔离了三个实现文件:
| 适配文件 | 用途 |
|---|---|
| api_linux.cpp | Linux 平台适配层 |
| api_win.cpp | Windows 平台适配层 |
| api_unknow.cpp | 未知 OS 或无 OS(裸机/RTOS)适配层 |
从代码结构推断,GuiLite 的跨平台策略是:平台相关的只有极小一部分"系统能力"(线程、定时器、休眠、framebuffer 提供等),其余全部是平台无关的纯 C++ 绘制与控件逻辑。因此在 MCU 上移植时,只需要按 HowToUse.md 的说明,在 api_unknow.cpp 中实现 thread_sleep 等平台函数即可。官方文档还强调:代码只使用 C++ 的基本特性(类和虚函数),这让 C 语言初学者也能快速读懂。
核心功能全景
除基础 GUI 外,README_zh.md 列出了一组实用功能,是其与普通"玩具级" GUI 库拉开差距的地方:
- ☁️ "云 + 物联网"解决方案:宣称可驾驭全球范围的 IoT 业务,配套的 HostMonitor / HelloAzureIoT 示例展示了设备上云监控与全球设备追踪。
- 🔣 多语言支持(UTF-8 编码);📀 支持视频播放(如 HelloFFmpeg 示例)。
- 🔨 资源制作工具:用于定制自己的字体/图片资源(Lattice 点阵字体、Freetype 矢量字体均有对应示例)。
- 📐 所见即所得(WYSIWYG)的 GUI 布局工具:可视化拖拽布局,配合 HowLayoutWork.md 中基于
WND_TREE结构描述控件的布局方式。 - 📊 编译活跃度统计与实时分析:即代码遥测(Code Telemetry)。
- 📦 支持 3D 渲染(Hello3D 系列示例)与 Web 端运行。
- 🐋 支持 Docker 一键运行,官方给出的命令为:
sudo docker run -it --privileged -v /dev:/dev-share idea4good/gui-lite:latest bash /run.sh
注:仓库内不包含上述第三方配套工具(GuiLiteToolkit、GuiLitePreviewer、GuiLiteSamples、GuiLiteWeb)的源码,它们属于外部独立仓库;本仓库只提供 README_zh.md 所述的入口信息与相关示例截图。
快速上手:作为使用者集成 GuiLite
对于普通使用者,GuiLite 是纯头文件库,集成方式极其简单。按 documents/HowToUse.md 的说明,只需两步:
- 将
GuiLite.h(仓库根目录已提供)复制到你的应用中; - 在代码里定义宏并包含头文件:
#define GUILITE_ON // 注意:不要在包含 GuiLite.h 之后再重复定义此宏
#include "GuiLite.h"
// 你的业务代码:
关于 GUILITE_ON 宏:它在 src/CMakeLists.txt 中通过 ADD_DEFINITIONS(-DGUILITE_ON) 注入编译参数,用于控制编译开关(例如区分"库编译模式"与"应用包含模式")。使用者集成时需保证该宏定义在 #include 之前且不重复定义。
从源码构建:开发者模式
如果你想深入源码、自定义控件或向不同平台移植,则可以按如下方式构建库本身。
构建准备:一次性生成单一头文件 GuiLite.h
仓库根目录的 GuiLite.h 并不是手写的,而是由脚本 src/GenerateGuiLite.h.sh 自动合并生成的。该脚本的核心流程是:
- 把 src/core 下的
api.h、resource.h、theme.h、display.h、word.h、image.h、wnd.h合并为core.h; - 把 src/widgets 下的
button.h、dialog.h、keyboard.h、edit.h、label.h、list_box.h、slide_group.h、spinbox.h、table.h、wave_buffer.h、wave_ctrl.h合并为widgets.h; - 将
core.h+widgets.h拼接为GuiLiteRaw.h,并把core.cpp、widgets.cpp及各 adapter 的.cpp合并为GuiLiteRaw.cpp; - 清理重复的
#include与#pragma once,在首行加上#pragma once; - 将
GuiLite.cpp追加到GuiLite.h末尾,把声明与实现全部收进一个头文件; - 最后用
gcc -c -D GUILITE_ON test.cpp做编译自检。
执行命令(在本仓库中脚本位于 src 目录):
cd src
./GenerateGuiLite.h.sh
# 生成结果:仓库根目录的 GuiLite.h
这就是"单一头文件、零依赖"的由来:头文件里同时包含所有类的声明与实现,你只需 #include "GuiLite.h"。
Windows 构建(Visual Studio)
按 documents/HowToUse.md 的说明,前提是 Windows + Visual Studio 2013/2015/2017/2019:
- 用 Visual Studio 打开本仓库的 src/GuiLite.sln;
- 点击
Build Solution(生成解决方案); - 输出静态库
GuiLite.lib(Debug/Release 配置分别输出)。
若打开工程时报错,需要重新配置工程以匹配本机环境(如平台工具集),官方文档提供了配置示意图 documents/vs-configure.jpg。
Linux / macOS(含 amd64、树莓派)构建
使用 CMake + Make 即可:
cd src
cmake .
make
# 输出:src/libGuiLite.a
src/CMakeLists.txt 中做了三件关键事情:设置库输出目录到工程根目录(LIBRARY_OUTPUT_PATH)、加入 -DGUILITE_ON 编译定义、并分别收集 core(含 adapter)与 widgets 源码编译为 静态库(注释中同时保留了 SHARED 动态库的构建方式)。
ARM Linux 交叉编译
前提是安装交叉编译器:
# ARM32:
sudo apt-get install g++-arm-linux-gnueabi gcc-arm-linux-gnueabi
# ARM64:
sudo apt-get install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu
然后指定交叉编译器进行 CMake 配置并编译:
cd src
# ARM32:
cmake -D CMAKE_C_COMPILER="/usr/bin/arm-linux-gnueabi-gcc" -D CMAKE_CXX_COMPILER="/usr/bin/arm-linux-gnueabi-g++" .
# ARM64:
cmake -D CMAKE_C_COMPILER="/usr/bin/aarch64-linux-gnu-gcc" -D CMAKE_CXX_COMPILER="/usr/bin/aarch64-linux-gnu-g++" .
make
# 输出:src/libGuiLite.a
MCU(Keil)构建
对于任意单片机平台(如 STM32):
- 前提:安装 Keil uVision 5.6 或以上版本;
- 用 Keil 打开本仓库的 src/GuiLite.uvprojx 工程;
- 在
core/adapter/api_unknow.cpp中实现平台相关函数(例如thread_sleep)以满足目标环境需求——这是裸机/RTOS 移植的唯一适配点; - 在"Options for Target"中选择设备类型(工程默认 STM32F103ZE);
- 编译输出静态库
GuiLite.lib。
设计原理:界面元素管理与图形绘制
documents/HowToWork-cn.md 给出了最精辟的概括:GuiLite 只做两个工作——界面元素管理和图形绘制。理解这一划分,就理解了整个库的架构。
两大职责
界面元素管理包括:
- 添加/删除界面元素(按钮、标签、对话框等控件),设置对应的文字及位置信息;
- 用户输入消息传递:根据用户输入(触摸坐标)寻找受影响的界面元素,并回调对应的处理函数;
- 用户自定义消息传递:用户可以自定义消息响应函数并自主产生消息,消息产生时对应响应函数被调用。
图形绘制包括:
- 基本的点、线绘制(画点、矩形、横线、竖线等);
- 设置绘制图层:多图层场景下,绘制时需要给出图层的索引值;
- 图层处理:图层界面发生变化(如打开/关闭对话框)时,GuiLite 决定各图层上的像素点哪些最终显示在屏幕上。
👉 关键设计:图形绘制不依赖界面管理,可以独立存在。官方文档特别指出:在资源有限的单片机环境,有时不需要界面元素管理,直接进行图形与文字的绘制即可——这给了开发者极大的裁剪自由度。
界面元素树:connect / disconnect
所有界面元素都继承自 c_wnd 类(源码见 src/core/wnd.h)。当对象被实例化时,只是创建了一个"孤独"的元素——没有父母、没有兄弟姐妹、不响应任何输入。
元素被纳入管理的过程,就是调用 connect():把自身、子窗口系列与父窗口连接起来,形成一棵完整的 UI 窗口树。此后:
- 所有元素可被遍历/添加/删除;
- 元素开始响应触摸与消息回调。
典型的交互流程(以按下 dialog 上的 button 为例):手指位置(x,y)被传入树的根部(root),从 root 开始寻找哪个 dialog 被点中、dialog 上哪个 button 被点中,再调用该 button 的点击回调函数(一般做状态修改与重绘)。
删除元素则调用 disconnect():切断与父窗口、子窗口的链接,从树上摘下,不再响应触控;对象本身不会被销毁。官方文档给出的典型应用场景是软键盘的创建/退出。
核心接口(来自 HowToWork-cn.md 的函数注释,实现在 src/core/core.cpp):
| 函数 | 作用 |
|---|---|
connect |
把自己、子窗口系列与父窗口连接成完整 UI 窗口链条 |
load_child_wnd |
连接一系列子窗口,形成完整的 UI 窗口链条 |
disconnect |
切断自身与父/子窗口的联系,不再响应输入与消息 |
get_wnd_ptr |
按窗口 ID 获得窗口指针 |
set_attr |
设置窗口属性:普通、失效、可见 |
set_wnd_pos |
设置窗口相对父窗口的位置与尺寸 |
get_wnd_rect / get_screen_rect |
获取相对父窗口 / 相对 UI 系统的位置信息 |
on_touch |
响应用户触控消息(按下/释放) |
on_key |
响应用户按键消息 |
notify_parent |
向父窗口传递 UI 消息并调用对应响应函数 |
show_window |
渲染自身及子窗口 |
图形绘制:三层图层模型
GuiLite 的图层模型分为 display 层 → surface 层 → frame 层 三个层次:
- display 层:对应物理显存,决定一个显示终端的最终显示效果;通常系统中至少有一个 display 层。
- surface 层:属于 display 层的一部分,为左右滑动而存在——每一张滑动页面对应一个 surface 层,surface 层决定了一个滑动页面的最终显示效果;通常 1 个 display 层对应多个 surface 层。
- frame 层:属于 surface 层的一部分,用于叠加界面元素。
在代码中,这一模型由 src/core/display.h 的 c_display 与 c_surface 两个类实现:
c_display是显示终端(物理显存)的抽象,SURFACE_CNT_MAX被定义为 6,即最多支持 1 个 root + 5 个滑动页面;- 图层优先级由枚举
Z_ORDER_LEVEL定义(LEVEL_0最低 →LEVEL_2最高),系统默认支持 3 层遮挡关系:视图背景层、对话框层、keyboard/spinbox 控件层; c_surface内部维护c_layer数组(每个图层有独立 framebuffer 与可视矩形),绘制时通过activate_layer(文档中称set_overlap_zone)设置活动矩形,实现图层的动态遮挡与叠加。
关键渲染接口
c_display 的核心接口(完整注释见 HowToWork-cn.md):
| 接口 | 说明 |
|---|---|
c_display |
构造函数:phy_fb 物理 framebuffer 指针、显示宽高、surface 宽高、color_bytes 颜色深度、surface_cnt 滑动页面个数、gfx_op 外部绘制接口(适配非 framebuffer 渲染) |
alloc_surface |
分配 surface/滑动页面,参数为使用者 ID 与图层数量 |
merge_surface(源码中为 swipe_surface) |
横向组合两个 surface,实现滑动切换动画 |
get_updated_fb |
获取 display 的 framebuffer 指针(带强制更新开关,可判断是否有新帧) |
snap_shot |
生成当前显示的快照,输出为 BMP 文件 |
c_surface 的核心接口:
| 接口 | 说明 |
|---|---|
draw_pixel / fill_rect / get_pixel |
带图层参数(z_order)的像素级绘制与读取 |
draw_pixel_on_fb / fill_rect_on_fb |
底层渲染(直写 framebuffer) |
draw_hline / draw_vline / draw_line / draw_rect |
基本图形绘制 |
set_overlap_zone(源码中为 activate_layer) |
设置指定图层的可视区域,按优先级自动上下叠加 |
flush_screen |
将 surface 指定矩形区域一次性刷到显示屏 |
is_valid |
判断给定矩形是否在 surface 范围内 |
官方文档还指出:为了发挥 GPU 加速能力,可以通过改写
draw_xxx/fill_xxx函数接入 GPU 特性来提升绘制效率;扩展绘制(画圆、画曲线等)可直接在对应的绘制源文件中添加函数接口。
源码地图与学习路线
README_zh.md 与 HowToWork-cn.md 共同给出了清晰的学习路径与源码地图。
官方推荐的学习步骤
- 编译 GuiLite 库;
- 编译、调试 HelloXXX 实例程序;
- 研读、修改 100+ 行的
HelloXXX/UIcode/UIcode.cpp源代码(注意:HelloXXX 示例位于外部 GuiLiteSamples 仓库,本仓库不包含); - 研读
widgets目录下的代码; - 研读
core目录下的代码; - 扩展/开发自己的 GUI 库。
core 目录文件注释(重要程度 / 推荐学习时间)
| 重要程度 | 文件 | 代码简介 | 学习时间 |
|---|---|---|---|
| ★★★ | wnd.h | UI 元素的基本类,定义所有 UI 元素信息、绘制及管理办法 | 1.5 小时 |
| ★★ | display.h | 生成显示设备,设定 surface 数目(一个 surface 对应一个滑动页面) | 0.5 小时 |
| word.h | 显示文字 | < 1 小时 | |
| image.h | 绘制位图,支持 16 bits 和 32 bits | < 0.5 小时 | |
| resource.h | 资源(字体/位图)定义 | < 0.5 小时 | |
| api_linux.cpp | Linux 适配层 | < 0.5 小时 | |
| api_win.cpp | Windows 适配层 | < 0.5 小时 | |
| api_unknow.cpp | 无 OS 或其他 OS 适配层 | < 0.5 小时 |
widgets 目录文件注释
| 难度 | 文件 | 代码简介 | 学习时间 |
|---|---|---|---|
| label.h | 标签控件的绘制 | < 0.5 小时 | |
| button.h | 按钮控件的绘制及用户点击响应函数 | < 0.5 小时 | |
| table.h | Table 控件的绘制 | < 0.5 小时 | |
| dialog.h | 对话框的绘制及管理方法 | < 0.5 小时 | |
| ★ | keyboard.h | 键盘控件的绘制及用户点击响应函数 | 0.5 小时 |
| ★★ | list_box.h | List 控件的绘制及用户点击响应函数 | 1.5 小时 |
| ★★ | spinbox.h | Spinbox 控件的绘制及用户点击响应函数 | 1.5 小时 |
| ★★ | edit.h | Edit 控件的绘制及用户点击响应函数 | 1.5 小时 |
| ★ | slide_group.h | 多屏 GUI 的实现及划屏切换操作 | 1.5 小时 |
| ★★★ | wave_buffer.h | 波形数据的缓冲管理 | 1.5 小时 |
| ★★★ | wave_ctrl.h | 通过波形数据绘制实时波形控件 | 1.5 小时 |
速成路线图
HowToWork-cn.md 给出了一条 4 步速成路线:
- 精读
wnd.cpp(本仓库为 src/core/core.cpp)中的connect、on_touch、on_key函数,理解界面元素的串联方式、触控响应与硬按键响应的基本原理; - 快速浏览绘制源文件中的
draw_xxx系列函数,熟悉基本绘制接口;精读c_surface构造函数,理解其成员关系; - 精读
button.cpp(本仓库为 src/widgets/widgets.cpp),初步掌握界面元素的基本开发方法; - 对照 HelloStar 实例在不同平台的入口(BuildLinux/main.cpp、BuildMFC/HelloStarDlg.cpp、BuildSTM32F103-Keil/USER/main.c)理解构建各类应用的方法。
配套深入文档
仓库 documents 目录还提供了四份深入文档,均以 GuiLiteSamples::HostMonitor 为实例:
- HowToUse.md:集成与各平台构建方法(上文已充分展开);
- HowToWork-cn.md:设计原理与代码注释(上文已充分展开);
- HowLayoutWork.md:控件布局方法——所有控件由
WND_TREE结构体与对应的.xml.cpp文件描述,分 slide group(滑动页组)、single slide(单页)、dialog(对话框)三种布局场景; - HowMessageWork.md:消息传递机制——实时绘制波形消息、点击按钮消息、左右划屏翻转消息三条调用链的时序图;
- UML.md:核心 UML 示意图,与 documents/uml-class.png、documents/uml-ui-process.png 配套。
Demo 展示墙:各平台各场景验证
README_zh.md 声称所有 Demo 零依赖、100% 编译通过、可直接运行,且大部分 demo 的 UI 代码只有 100 行左右(示例代码位于外部 GuiLiteSamples 仓库,本文仅列出仓库 documents 中提供的演示素材与其场景分类)。
单片机平台(STM32 等):Hello3D(3D 渲染)、HelloWave(波形)、HelloParticle(粒子)、HelloStar(星形粒子)、Hello3Dwave(3D 波浪)、HelloNoTouch(软键盘)、HelloMario(游戏)、HelloCircle(3D 圆环)、Hello3Ddonut(3D 甜甜圈)、HelloTimer(定时器)、HelloMolecule(分子运动)、HelloPendulum(钟摆特效)。
IoT 功能:HostMonitor(云上监控 IoT 设备、代码遥测实时分析)、HelloAzureIoT(全球范围追踪 IoT 设备)。
多语言 / 设计工具 / 视频:HelloFont(点阵字体)、HelloFreetype(FreeType 矢量字体)、HelloJPG(快速渲染 JPG)、HelloFFmpeg(FFmpeg 播放视频);以及所见即所得的 GUI 布局工具(Layout GUI)。
UI 控件实现:HelloGuiLite(模拟 Windows UI)、HelloScroll(滚动控件)、HelloWidgets(控件综合用法)、HelloNets(3D 网格)、HelloTransparent(透明对话框)、HelloSlide(滑动手势视图)。
跨平台实现:HostMonitor 分别运行于 Windows、Mac、Android、Windows Mixed Reality(MR 头显)、Linux、iPhone;GuiLite 3D 场景运行于 Web 端。
苹果平台:3D 与波浪效果运行于 Apple Watch(iWatch.hello3D、iWatch.helloWave),粒子效果运行于 iPhone(iOS.particle)。
社区交流
GuiLite 欢迎开发者加入其开发者大家庭。官方提供的交流渠道为开发者 QQ 群(群号 875721211),二维码图片见 documents/qq.group-7.png。官方文档同时声明 GuiLite 采用 Apache 2.0 许可证,并提供了 Gitee 快速链接便于国内开发者访问。
总结:GuiLite 用 4 千行代码、单一头文件、零依赖的设计,换取了一条从 24 MHz 单片机到 PC、手机、Web 的通用 GUI 路径。它的"界面元素管理 + 图形绘制"双职责架构、connect/disconnect 窗口树、三层图层模型(display/surface/frame)构成了理解全部示例与二次开发的基石。无论你是想在 STM32 上快速出界面,还是想研究一个极简 GUI 内核的完整实现,按本文的构建命令与学习路线走下去,都能快速上手。

