GuiLite 中文技术指南:4 千行全平台纯头文件 GUI 库的架构、构建与实战

原创2026-10-03 10:01:481,730 阅读
文章标签:前端UI组件嵌入式物联网

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 场景的底气所在。从源码结构看,这一极低开销来源于两层设计:

  1. 纯头文件、零依赖:不依赖标准图形库、字体库或操作系统 GUI 子系统;
  2. 渲染直达显存:c_surface 的底层绘制函数(draw_pixel_low_level、fill_rect_low_level)直接写 surface 的 framebuffer,且只在需要时通过 flush_screen 一次性同步到物理显存。

GuiLite 为什么如此轻量

上图来自仓库 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 的说明,只需两步:

  1. 将 GuiLite.h(仓库根目录已提供)复制到你的应用中;
  2. 在代码里定义宏并包含头文件:
#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 自动合并生成的。该脚本的核心流程是:

  1. 把 src/core 下的 api.h、resource.h、theme.h、display.h、word.h、image.h、wnd.h 合并为 core.h;
  2. 把 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;
  3. 将 core.h + widgets.h 拼接为 GuiLiteRaw.h,并把 core.cpp、widgets.cpp 及各 adapter 的 .cpp 合并为 GuiLiteRaw.cpp;
  4. 清理重复的 #include 与 #pragma once,在首行加上 #pragma once;
  5. 将 GuiLite.cpp 追加到 GuiLite.h 末尾,把声明与实现全部收进一个头文件;
  6. 最后用 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:

  1. 用 Visual Studio 打开本仓库的 src/GuiLite.sln;
  2. 点击 Build Solution(生成解决方案);
  3. 输出静态库 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):

  1. 前提:安装 Keil uVision 5.6 或以上版本;
  2. 用 Keil 打开本仓库的 src/GuiLite.uvprojx 工程;
  3. 在 core/adapter/api_unknow.cpp 中实现平台相关函数(例如 thread_sleep)以满足目标环境需求——这是裸机/RTOS 移植的唯一适配点;
  4. 在"Options for Target"中选择设备类型(工程默认 STM32F103ZE);
  5. 编译输出静态库 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 层的一部分,用于叠加界面元素。

GuiLite 图层关系示意图

在代码中,这一模型由 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 共同给出了清晰的学习路径与源码地图。

官方推荐的学习步骤

  1. 编译 GuiLite 库;
  2. 编译、调试 HelloXXX 实例程序;
  3. 研读、修改 100+ 行的 HelloXXX/UIcode/UIcode.cpp 源代码(注意:HelloXXX 示例位于外部 GuiLiteSamples 仓库,本仓库不包含);
  4. 研读 widgets 目录下的代码;
  5. 研读 core 目录下的代码;
  6. 扩展/开发自己的 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 步速成路线:

  1. 精读 wnd.cpp(本仓库为 src/core/core.cpp)中的 connect、on_touch、on_key 函数,理解界面元素的串联方式、触控响应与硬按键响应的基本原理;
  2. 快速浏览绘制源文件中的 draw_xxx 系列函数,熟悉基本绘制接口;精读 c_surface 构造函数,理解其成员关系;
  3. 精读 button.cpp(本仓库为 src/widgets/widgets.cpp),初步掌握界面元素的基本开发方法;
  4. 对照 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 内核的完整实现,按本文的构建命令与学习路线走下去,都能快速上手。

登录后查看全文
GuiLite