简介:uCGUIBulider 4.0.0.0是一套面向嵌入式系统开发者的图形用户界面设计工具,与uCGUI轻量级图形库配套使用,旨在简化微控制器上复杂UI的构建流程。压缩包体积仅7.87MB,包含430个文件,其中以C/C++头文件、静态库、可执行程序及批处理脚本为主,既有完整的源码工程与工程文件,也有编译好的工具程序、依赖动态库和VC2008环境配置脚本,支持在Windows 8 64位系统上直接展开使用。借助可视化拖放控件、属性设置和实时预览,开发者能够快速完成智能家居、车载显示、医疗仪器等场景的界面设计,并自动生成可移植的底层代码,显著减少手工编码工作量。资源已有178人浏览学习,适合正在学习uCGUI框架或需要为嵌入式项目快速搭建UI界面的工程师参考。
1. uCGUIBulider4.0.0.0:可视化拖拽生成uC/GUI界面的落地工具
uCGUIBulider 4.0.0.0 是面向 uC/GUI 图形库的可视化界面设计工具,很多人在网上搜"uCGUIBuilder"或"uC-GUI 界面设计器",指的都是这一套东西。它解决一个很现实的嵌入式问题:屏幕没多大,菜单却有七八层,每个界面都手写窗口创建和回调的话,改一次布局等于重写一遍逻辑。用这个工具拖控件、设属性、点生成,C 代码就直接出来,挂进工程就能编译。适合用裸机或 RTOS 做屏显项目、被硬编码坐标折磨的单片机工程师,也适合刚接触 uC/GUI 想快速看到界面的初学者。
2. 先认识界面与工作流:四个面板和三个固定动作
2.1 打开工具先分清四个区域
我第一次打开 uCGUIBulider 时把它当成普通画图工具,拖了半个小时后发现控件位置完全对不上。后来把它拆开看,其实它和大多数 GUI 编辑器一样,主窗口由四块组成:左侧控件工具箱、中间画布、右侧属性面板、底部工程资源窗口。
控件工具箱里是常用的基础控件:按钮、文本、复选框、滑条、进度条、下拉框,对应 uC/GUI 里的 BUTTON、TEXT、CHECKBOX、SLIDER、PROGRESSBAR、DROPDOWN 控件类。把控件拖到画布上,右侧属性面板就会同步显示它的坐标、宽高、控件 ID、字体、对齐方式。底部工程资源窗口管理整个工程的对话框、字体、位图、回调函数,像一棵资源树,生成代码时也是从这棵树上挑资源打包。
清楚四个区域之后,整个使用流程固定成三个动作:往画布放控件、在属性面板改参数、在工程窗口点生成。后面无论做多复杂的菜单,本质都是这三步的循环。uCGUIBulider 的价值不在于帮你画一个漂亮界面,而在于把"界面长什么样"和"代码怎么写"绑在一起,改布局就等于改数组,逻辑和表现能分开迭代。
2.2 分辨率、深度与颜色格式:画布和屏幕必须对齐
动手画之前有一组参数要先确认:屏幕分辨率、位深、颜色格式。工具允许在工程属性里设置目标屏幕的宽和高,单位是像素,常见的有 320x240、800x480 这些。分辨率设错最直接的影响是画布尺寸和真实屏幕不一致,控件放上去后要么超出屏幕边界被裁掉,要么只占屏幕一角。
这里最容易忽略的是颜色格式。uC/GUI 的底层是 LCD 驱动适配层,支持 RGB565、RGB888、BGR565 等。如果你的屏是 RGB565,生成的代码会把颜色值打包成两个字节,写入显存时高低字节顺序必须和屏模组匹配。工程属性里选错,界面整体偏色,红色变蓝色、蓝色变绿色,排查起来非常费劲。常见做法是:先看 LCD 驱动例程里的初始化配置,照着它选,不要凭着对屏规格书的印象填。
位深对应 uC/GUI 的 LCD_BITSPERPIXEL 宏,决定颜色字节数和后面图片、字体转换时的像素对齐。选错的话图片显示会花屏或错位,尤其当你在同一个工程里同时用图片和字体时,转换工具的像素格式和工程属性不一致,运行时的颜色数据会被重新解释,显示结果完全不可预期。我的经验是先读一遍 LCD 例程里的配置,再回工具里填,这一项填错了后面返工成本最高。
2.3 坐标系与对话框:一个对话框就是一块独立画布
uCGUIBulider 里的"界面",本质上是 uC/GUI 的对话框。对话框是一个独立窗口,所有控件都挂在它上面。画布的白色区域就是一个对话框,控件坐标是相对对话框左上角的,不是屏幕绝对坐标。这个设计意味着对话框移动时,控件不会跟着自动重排,除非你在初始化回调里动态计算位置。
这个特性影响两点:一是你框选全部控件整体拖动时,它们的相对位置保持不变,但绝对坐标整体偏移,这个偏移会原样写进生成代码;二是如果你的界面需要居中显示,不能靠修改对话框创建坐标完成,只能在 WM_INIT_DIALOG 里按屏幕分辨率重新算一遍控件偏移。
操作上很简单:从工具箱点中一个文本控件,在画布上拖一个区域,属性面板里就能改文本内容、字体、对齐方式。先不改,直接点 Generate,工程目录下就有了带初始化数组和回调函数骨架的 C 文件。一行代码没写,一个能编译的对话框已经出来了。很多人第一次用会被这个速度惊到,这也是这个工具至今还在嵌入式 GUI 领域被不断下载的原因。
3. 从画布到工程:生成代码的结构、编译集成与参数调整
3.1 点击 Generate 之后发生了什么
点击 Generate 之后,工具会根据当前对话框生成两个关键文件:对话框资源文件、回调与创建函数文件。把这两个文件加进工程,主程序里调用创建函数就能把界面弹出来。下面是一个简单对话框生成结果的关键片段,和 uCGUIBulider 4.0.0.0 默认输出风格一致:
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = { { TEXT_CreateIndirect, "txtTitle", ID_TEXT_TITLE, 0, 0, 0, 240, 30, 0, 0, 0, 0, 0 }, { BUTTON_CreateIndirect, "btnOk", ID_BUTTON_OK, 10, 50, 100, 30, 0, 0, 0, 0, 0, 0 }, { BUTTON_CreateIndirect, "btnCancel", ID_BUTTON_CANCEL, 130, 50, 100, 30, 0, 0, 0, 0, 0, 0 }, }; static void _cbDialog(WM_MESSAGE * pMsg) { switch (pMsg->MsgId) { case WM_INIT_DIALOG: TEXT_SetText(WM_GetDialogItem(pMsg->hWin, ID_TEXT_TITLE), "System Info"); break; case WM_NOTIFY_PARENT: if (pMsg->Data.v == WM_NOTIFICATION_RELEASED) { int Id = WM_GetId(pMsg->hWinSrc); if (Id == ID_BUTTON_OK) { /* 用户点击了 OK */ } else if (Id == ID_BUTTON_CANCEL) { GUI_EndDialog(pMsg->hWin, 0); } } break; default: WM_DefaultProc(pMsg); } }这段代码的逻辑是:_aDialogCreate 数组描述对话框里每个控件的创建信息,_cbDialog 是对话框的回调函数,处理初始化消息和控件通知。两段合在一起就是 uC/GUI 对话框运行时的全部骨架。工具把这两个部分生成好,你只需要在回调里填业务逻辑。
参数说明:TEXT_CreateIndirect 和 BUTTON_CreateIndirect 是控件间接创建函数,参数依次是控件类型、控件名、控件 ID、x、y、宽、高、附加标志、附加参数、字体 ID、字体颜色、背景色。其中第 4、5 个参数是坐标,第 6 个是宽度、第 7 个是高度,单位都是像素,0 表示不设置,不设置的值会走控件默认属性。控件名是字符串标签,运行时只作为调试标识,不影响逻辑,但建议保持和功能一致。
3.2 把生成代码接进工程:文件名、头文件与初始化
生成文件默认有固定命名风格,常见的像 DIALOG_1.c、DIALOG_1.h 这种。你需要做三件事:把 .c 文件加进编译器工程、把 .h 文件所在路径加进包含目录、在 main 里 include 后调用创建函数。创建函数的命名一般和对话框名相关,比如 CreateDialog1(void)。
我一般会把生成代码和驱动代码分开目录放,因为工具一旦重新生成,会覆盖原文件。如果手改过生成文件,下次点生成改动会直接消失,这一点后面避坑章节会专门讲。头文件里通常还包含控件 ID 的枚举,比如 ID_TEXT_TITLE、ID_BUTTON_OK,回调里依赖这些 ID 做分支,不到万不得已不要改动。
常见集成顺序是:
- 把 DIALOG_1.c 复制进工程源码目录。
- 在 main 函数所在文件 include "DIALOG_1.h"。
- 在图形库初始化之后调用 CreateDialog1()。
- 根据界面模式选择消息循环方式,模态界面进 GUI_ExecDialogCreate,非模态界面留在 WM_CreateDialogBox 管理。
有一点容易混淆:WM_CreateDialogBox 和 GUI_ExecDialogCreate 的区别。前者创建后立即返回,调用线程可以继续做别的事,界面生命周期交给窗口管理器;后者会进入对话框消息循环,直到对话框被关闭才返回。如果你的界面是模态窗口,用 GUI_ExecDialogCreate 最简单;如果只是作为主界面的一部分,用 WM_CreateDialogBox 更合适,这也是 4.0.0.0 生成代码里默认不带 Exec 的原因。
3.3 控件属性面板里的几个关键参数
属性面板里参数很多,但真正影响行为的是少数几个。控件 ID 决定回调里能区分哪个控件被操作,建议按功能命名而不是按序号命名,比如 ID_BUTTON_SAVE、ID_BUTTON_CANCEL,维护时一眼能看懂。Tab 顺序决定键盘焦点在控件间切换的次序,在工具里可以用列表调整,做键盘导航类产品时必须关注,普通触摸屏界面可以不管。
字体参数是一个下拉选择,默认是 GUI_FONT_DEFAULT 这类西文字体。想要中文字体,需要先在工程资源里添加并生成字体文件,这一块的坑集中在第 4 章。对齐方式分水平左中右和垂直顶中底,生成代码对应 TEXT_SetTextAlign 的内部实现。
还有一类控件特有的附加标志,比如 BUTTON 的 GUI_BUTTON_NOTIFY、CHECKBOX 的 GUI_CHECKBOX_NOTIFY,控制控件是否向父窗口发送通知消息。默认很多控件是不发通知的,如果发现回调里始终收不到某个控件的 WM_NOTIFY_PARENT,第一反应应该是检查这个标志,而不是怀疑回调写错了。
3.4 与 uC/GUI 版本匹配:API 和回调风格的差异
uCGUIBulider 4.0.0.0 生成的代码主要面向特定 API 阶段的 uC/GUI。如果你手头的图形库版本较老或较新,有些函数可能改名,消息参数的取法也可能有差异。比如部分版本里 WM_NOTIFY_PARENT 的附加数据通过 pMsg->Data.v 取,另一部分版本则把通知细节放进 pMsg->Data.p 指向的结构体里再取。
遇到这类差异,我的处理方式不是改生成器的输出,而是在自己工程里加一层适配。例如回调里统一通过 WM_GetId 拿控件 ID,不依赖用户自定义消息的附加字段;初始化统一在 WM_INIT_DIALOG 里完成,不在创建数组里塞太多自定义参数。这样工具重新生成代码后,适配层不用跟着变,工程照常编译。
4. 字体与图片资源转换:中文显示和位图导入的几个硬门槛
4.1 为什么中文是硬门槛
uC/GUI 本身不自带中文字库,默认字体只覆盖西文字符集,直接往 Text 控件里写中文,运行时显示的是一堆空心方块。原因是 uC/GUI 的字体系统基于 Unicode 编码映射字形数据,字体文件里没收录的字符无法显示。所以要让界面显示中文,必须先准备一个包含所需字符的字体文件,再用配套的字体转换工具生成 uC/GUI 可识别的 C 代码字体。
这一步是 uCGUIBulider 工作流里最容易被低估的部分。很多人控件拖好了、代码生成完了,一看中文全是方块,到处找补丁,实际上问题出在工程里根本没挂中文字体资源。工具本身不负责帮你打包字库,它只负责在控件属性里引用你已经转换好的字体变量。
4.2 用字体转换工具生成字体 C 文件
字体转换工具是独立运行的,不集成在 uCGUIBulider 主界面里。常见流程是:加载 TTF 或 TTC 字体文件,选择目标字符表,设置字号和抗锯齿选项,导出一个 C 文件。中文字体字符量大,生成的文件体积比西文字体大很多,转换时参数设置直接影响代码体积和显示效果。
工具导出时有一组参数,我按经验整理了建议值:
| 参数 | 作用 | 建议 |
|---|---|---|
| 字号 | 决定字形点阵大小 | 按设计稿定,别小于 12 |
| 抗锯齿 | 是否生成灰阶过渡 | 小屏用 4 级灰阶 |
| 字符范围 | 包含的 Unicode 码位 | 只放用得到的字符 |
| 编码格式 | 内部映射表宽度 | 保持默认,与主工程一致 |
| 像素格式 | 颜色位深对齐 | 必须与 LCD 位深一致 |
导出后的字体文件是一个 C 数组,包含字形位图数据和字符映射索引。把 C 文件加进工程后,还要回 uCGUIBulider 里刷新字体列表,新字体才会出现在控件属性的字体下拉框里。有的版本需要手动把字体变量名填进文本控件的字体字段,不会自动识别。中文字体这块没有捷径,字符表选多了 Flash 吃紧,选少了生僻字显示方块,属于典型的平衡题。
4.3 位图导入的两种方式
图片资源的处理路径和字体类似。uC/GUI 支持把 BMP 直接转换成 C 数组,也支持从文件系统里加载 PNG、JPEG。uCGUIBulider 4.0.0.0 里常配合位图转换工具使用,把 BMP 转成 C 文件形式存储,生成的是一个包含图像数据和格式信息的 C 数组。
转换参数里最重要的是像素格式和压缩选项。像素格式必须和 LCD 一致,比如 LCD_RGB565 对应转换器里的 RGB565 输出,不一致时显示会花屏。压缩选项一般选 RLE 压缩能减少图片数据体积,代价是显示时 CPU 要做解压处理,速度稍慢。如果图片是静态图标或背景,推荐 RLE;如果是频繁变化的动态区域,用不压缩反而更省 CPU,因为省掉了每次显示前的解压耗时。
生成的位图 C 数组会定义一个 IMAGE 结构变量,引用时需要把结构变量名填给控件的 Image 属性。常见错误是只把数组名填了进去,实际上应该填 IMAGE 结构变量名,数组名是给结构体内部使用的,控件读取的是结构体。这个错误很隐蔽,编译不报错,运行时图片直接不显示或显示一条黑带。
4.4 外部存储与流位图
当界面里大量使用图片、照片级背景或者大字号字体时,C 数组方案会把整个程序镜像撑得很大。硬件 Flash 放得下的时候问题不大,但芯片 Flash 紧张时就要考虑外部存储方案。uC/GUI 提供流位图机制:图片数据以压缩文件形式放在外部 Flash,显示时通过 GUI_JPEG_Draw、GUI_PNG_Draw 这类带 _GetData 接口的回调按需读取。
uCGUIBulider 本身生成代码时不会自动生成文件系统读取逻辑,你需要自己写 _GetData 回调,返回一帧数据给图形库。这个方案的边界在控制器必须能访问外部存储,且访问速度不能太慢。如果外部 Flash 挂在低速 GPIO 模拟 SPI 上,整屏重绘时会明显感觉刷新卡顿,尤其在菜单切换瞬间。
我的经验是:图片类资源少于十张时优先用 C 数组,省事且稳定;超过这个数量再考虑流位图。中等规模工程里,字体和图片加在一起的体积经常比代码本身还大,这个判断能帮你省下不少调优时间。
5. 避坑指南:坐标、回调、编码与数据体积的五个坑
5.1 控件坐标必须在对话框范围内
现象:生成代码编译通过,上电后界面上某些控件就是看不到,怎么找都找不到。
原因:uCGUIBulider 的画布可以画出对话框窗口大小,也可以把控件拖到对话框外的画布区域。拖出去之后,工具依然生成合法的坐标值,编译器不报错,因为坐标在运行时才被控件创建函数使用。控件创建时坐标是负数或超过分辨率上限,uC/GUI 在创建阶段不做越界检查,只是不回显。
解决:在点生成之前打开工程资源窗口,逐个检查控件坐标是否落在对话框矩形内。也可以把对话框整体放大一点,再框选全部控件拖回画布可视区域。最保险的做法是生成后搜索 x、y 小于 0 的初始化行,手动修正,别等到上板再排查。
5.2 控件通知收不到:附加标志没开
现象:回调里写了按钮的事件处理,但按钮按下去之后函数不执行。
原因:BUTTON 控件默认不发送 WM_NOTIFICATION_RELEASED 通知,除非创建时带上了 GUI_BUTTON_NOTIFY 附加标志。uCGUIBulider 属性面板里这一项如果没勾选,生成代码就是不带通知的,回调自然什么都没有收到。
解决:选中按钮,在属性面板里勾选 Notify 相关标志,重新生成代码。注意重新生成后要把新文件替换进工程,而不是继续用旧文件调试,否则你会怀疑是自己代码写错,查半天还在原地。
5.3 中文显示方块或乱码:字体映射没生效
现象:字体转换 C 文件已经加进工程,但 Text 控件里的中文还是不显示,有些字显示、有些字是方块。
原因:一类原因是字体转换时字符表不全,生僻字或标点没在表里;另一类原因是 uCGUIBulider 里文本控件的字体属性没有指向转换后的字体变量,还在用默认西文字体;还有一类是源文件编码和字体映射表编码不一致,编辑器把中文按 GB2312 存盘,字体映射按 Unicode 码位生成,两边对不上。
解决:转换字体前先确定用到的字符集,宁可多选几十个常用标点。给文本控件指定字体时,直接手动写入转换出来的字体变量名,别依赖自动选择。源文件统一用 UTF-8 编码保存,并在工程里保持一致。这一条属于翻车概率最高的坑,遇到中文问题先按这三条排查,能解决九成。
5.4 重新生成把手工改动覆盖了
现象:生成代码后手动在回调里加了一段逻辑,后来改了界面布局重新生成,发现之前加的代码全没了。
原因:工具的设计就是整文件覆盖。uCGUIBulider 不保留用户对生成文件的手工修改,也没有合并差异的选项,重新生成等于把整个文件替换成新版本。
解决:把需要维护的业务逻辑从生成文件里拆出去。回调里的具体业务放到独立 C 文件的独立函数中,生成文件只保留调用入口;或者每次手工改动前先复制一份备份。常见做法是生成后先备份,再修改,重新生成后比对差异,把旧文件里保留的逻辑手工搬回来。
提示:我现在的习惯是生成代码之后先复制一份到 backup 目录,再开始改。工具重新生成只当它是一份新图纸,改动永远在备份和业务层里做。
5.5 图片导入后 RAM 暴涨
现象:加了几张大图片后,程序镜像明显变大,运行时的 RAM 占用也上升,界面偶尔还闪烁。
原因:默认的位图 C 数组方案会把像素数据存放在只读区,但如果图片通过 GUI_BITMAP 结构被创建成动态对象,或者运行时被复制到 RAM 缓冲区作为屏上缓存,RAM 占用会成倍增长。像素格式不对时,图形库会做转换缓冲,也会额外占用 RAM。
解决:静态图标用 C 数组,大图片用流位图。在资源窗口里查看图片位深,确保与 LCD 一致,避免运行时转换。如果硬件有条件,把显存 DMA 和多帧缓冲放到外部 RAM,别和图片缓冲区挤同一块内存。RAM 暴涨这条通常是压死骆驼的最后一根稻草,提前规划好位深和存储方式能省掉很多调优时间。
6. 最后一步:在模拟器里验证生成结果,再上板
6.1 把生成代码放进模拟器工程
生成代码能编译只能算走完一半,界面实际长什么样、控件交互是否正常,最好先在一套模拟器里跑一遍。uC/GUI 的配套模拟器工程支持在 PC 上编译运行,把生成的 C 文件加进去,替换掉示例对话框,设置一个合适的屏幕分辨率,就能在电脑上看到完整的界面交互效果。这个环节能提前发现绝大多数坐标偏移、字体缺失和颜色格式问题,比上板后一个个查省太多时间。
具体做法是:先确认模拟器工程的 LCD 配置和目标屏一致,包括分辨率、位深、颜色格式,这三项不一致时模拟结果没有参考价值。然后把生成文件加进工程,在模拟器主文件里调用创建函数,编译运行。第一次跑通常会发现字体不对、控件位置偏出边界等问题,这些在模拟器里改起来比在板子上快得多。
6.2 多语言界面的一个实用技巧
uCGUIBulider 生成的文本控件默认把字符串写死在初始化数组里,多语言切换时要全部换文字会比较麻烦。一个实用的做法是:文本控件的内容不在生成文件里写死,而是在 WM_INIT_DIALOG 里根据当前语言查表设置。这样生成文件只保留控件结构,运行时按语言索引填充字符串,切换语言时只需要刷新界面文本,不需要重新生成代码。
配合模拟器验证也很方便:在模拟器里切换语言参数,跑一遍所有对话框,检查是否有文本溢出、对齐错位、字体缺失。这个习惯帮我解决了不少界面问题,尤其是阿拉伯语等排版方向特殊的语言,在模拟器里能直观看到对齐结果。从那以后我每次生成完都会在模拟器里跑一遍界面,确认坐标、字体、颜色三样都正常,才交给硬件联调。希望帮到你。
本文还有配套的精品资源,点击获取