从零写 OS 内核-第三十二篇:集成 LVGL —— 用开源 GUI 框架实现文本编辑器
"从零造轮子虽有趣,但工业级 GUI 需要成熟框架。
今天,我们将 LVGL(Light and Versatile Graphics Library)移植到我们的 OS,实现专业级文本编辑器!"
在前几篇中,我们从零实现了:
✅ Framebuffer 驱动
✅ 窗口管理器
✅ 位图文字渲染
✅ 画板工具
但手写 GUI 控件(按钮、输入框、滚动条)极其耗时。
真正的应用开发需要 成熟的 GUI 框架——
LVGL 正是为嵌入式系统设计的轻量级开源 GUI 库!
今天,我们就来:
✅ 移植 LVGL 到我们的 OS
✅ 实现 Display Driver 与 Input Driver
✅ 开发 LVGL 文本编辑器
✅ 集成到窗口管理器中
让你的应用拥有专业级 UI 体验!
🧩 一、为什么选择 LVGL?
LVGL 核心优势:
| 特性 | 说明 | |——|——| | 轻量级 | 仅需 64KB Flash + 10KB RAM | | 开源免费 | MIT 许可证,商用无忧 | | 功能丰富 | 按钮、滑块、文本框、列表、图表… | | 硬件抽象 | 通过 Display/Input Driver 适配任意平台 | | 活跃社区 | GitHub 15k+ stars,持续更新 |
💡 LVGL 被用于智能家居、医疗设备、汽车仪表盘等嵌入式产品!
🔌 二、LVGL 移植:Display Driver
LVGL 通过 Display Driver 将绘图命令转换为像素操作。
1. 实现 disp_flush
// user/lvgl/disp_driver.c
static void disp_flush(lv_disp_drv_t *disp,
const lv_area_t *area,
lv_color_t *color_p) {
// 1. 获取 Framebuffer
extern uint32_t *fb_buffer;
extern int fb_width;
// 2. 将 LVGL 颜色转换为 RGBA
for (int y = area->y1; y <= area->y2; y++) {
for (int x = area->x1; x <= area->x2; x++) {
lv_color_t color = *color_p;
uint32_t rgba = (0xFF << 24) |
(color.blue << 16) |
(color.green << 8) |
(color.red);
fb_buffer[y * fb_width + x] = rgba;
color_p++;
}
}
// 3. 通知 LVGL 刷新完成
lv_disp_flush_ready(disp);
}
2. 注册 Display Driver
void lvgl_init() {
// 1. 初始化 LVGL
lv_init();
// 2. 配置 Display Driver
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = disp_flush;
disp_drv.hor_res = 1024; // 屏幕宽度
disp_drv.ver_res = 768; // 屏幕高度
// 3. 注册
lv_disp_drv_register(&disp_drv);
}
🔑
disp_flush是 LVGL 与 Framebuffer 的桥梁!
🖱️ 三、LVGL 移植:Input Driver
LVGL 通过 Input Driver 处理鼠标/键盘事件。
1. 实现 indev_read
// user/lvgl/indev_driver.c
static bool indev_read(lv_indev_drv_t *drv, lv_indev_data_t *data) {
static int last_x = 0, last_y = 0;
static bool last_pressed = false;
// 1. 从 Display Server 获取鼠标状态
extern struct global_mouse_state mouse_state;
data->point.x = mouse_state.x;
data->point.y = mouse_state.y;
data->state = (mouse_state.buttons & 1) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
// 2. 检测点击事件
bool clicked = false;
if (data->state == LV_INDEV_STATE_RELEASED && last_pressed) {
clicked = true;
}
last_x = data->point.x;
last_y = data->point.y;
last_pressed = (data->state == LV_INDEV_STATE_PRESSED);
return clicked; // 是否有新事件
}
2. 注册 Input Driver
void lvgl_input_init() {
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER; // 鼠标
indev_drv.read_cb = indev_read;
lv_indev_drv_register(&indev_drv);
}
💡 LVGL 会自动处理按钮悬停、点击反馈等交互!
📝 四、文本编辑器实现
1. 创建主窗口
// user/text_editor.c
void text_editor_create() {
// 1. 创建主屏幕对象
lv_obj_t *scr = lv_scr_act();
// 2. 创建标题标签
lv_obj_t *title = lv_label_create(scr);
lv_label_set_text(title, "MyOS Text Editor");
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 10);
// 3. 创建文本区域(Text Area)
lv_obj_t *ta = lv_textarea_create(scr);
lv_textarea_set_one_line(ta, false); // 多行
lv_obj_set_size(ta, 600, 400);
lv_obj_align(ta, LV_ALIGN_CENTER, 0, 0);
lv_textarea_set_max_length(ta, 1024);
// 4. 创建状态栏
lv_obj_t *status = lv_label_create(scr);
lv_label_set_text(status, "Lines: 1 | Characters: 0");
lv_obj_align(status, LV_ALIGN_BOTTOM_MID, 0, -10);
// 5. 保存引用(用于更新)
editor.ta = ta;
editor.status = status;
}
2. 处理文本变化
static void ta_event_cb(lv_event_t *e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t *ta = lv_event_get_target(e);
if (code == LV_EVENT_VALUE_CHANGED) {
// 更新状态栏
const char *txt = lv_textarea_get_text(ta);
int lines = 1;
int chars = 0;
for (const char *p = txt; *p; p++) {
if (*p == '\n') lines++;
chars++;
}
char status[64];
sprintf(status, "Lines: %d | Characters: %d", lines, chars);
lv_label_set_text(editor.status, status);
}
}
// 在 text_editor_create 中注册回调
lv_obj_add_event_cb(ta, ta_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
3. 添加菜单栏(简化版)
void create_menu_bar() {
lv_obj_t *scr = lv_scr_act();
// 新建按钮
lv_obj_t *btn_new = lv_btn_create(scr);
lv_obj_set_size(btn_new, 80, 30);
lv_obj_align(btn_new, LV_ALIGN_TOP_LEFT, 10, 50);
lv_obj_t *label = lv_label_create(btn_new);
lv_label_set_text(label, "New");
// 打开按钮
lv_obj_t *btn_open = lv_btn_create(scr);
lv_obj_set_size(btn_open, 80, 30);
lv_obj_align(btn_open, LV_ALIGN_TOP_LEFT, 100, 50);
label = lv_label_create(btn_open);
lv_label_set_text(label, "Open");
// 绑定事件
lv_obj_add_event_cb(btn_new, btn_new_event, LV_EVENT_CLICKED, NULL);
lv_obj_add_event_cb(btn_open, btn_open_event, LV_EVENT_CLICKED, NULL);
}
🚀 五、集成到窗口管理器
1. Text Editor 应用入口
// user/text_editor_main.c
void _start() {
// 1. 连接到 Display Server
display_t *disp = display_connect();
display_create_window(disp, 800, 600);
// 2. 初始化 LVGL
lvgl_init();
lvgl_input_init();
// 3. 创建文本编辑器
text_editor_create();
create_menu_bar();
// 4. 主循环:处理 LVGL 任务
while (1) {
// 处理 Display Server 事件(鼠标/键盘)
process_display_events();
// LVGL 任务处理
uint32_t time_ms = get_system_time();
lv_timer_handler_run_in_period(5); // 5ms 刷新
// 提交帧
display_commit(disp);
usleep(10000); // 10ms
}
}
2. LVGL 与 Display Server 协同
- Display Server:提供鼠标/键盘事件 + Framebuffer
- LVGL:消费事件 + 绘制 UI
- Text Editor:业务逻辑(文件操作、状态更新)
✅ LVGL 完全运行在用户态,无需内核修改!
📁 六、部署与构建
1. LVGL 编译配置
// lv_conf.h (关键配置)
#define LV_COLOR_DEPTH 32
#define LV_COLOR_16_SWAP 0
#define LV_FONT_DEFAULT &lv_font_montserrat_14
#define LV_USE_TEXTAREA 1
#define LV_USE_LABEL 1
#define LV_USE_BTN 1
2. Makefile 集成
# user/Makefile
LVGL_DIR = ../lvgl
text_editor: text_editor.c $(LVGL_DIR)/lvgl.h
$(CC) $(CFLAGS) -I$(LVGL_DIR) \
-I$(LVGL_DIR)/src \
-o $@ $^ \
$(LVGL_DIR)/src/core/*.c \
$(LVGL_DIR)/src/widgets/*.c \
$(LVGL_DIR)/src/misc/*.c \
$(LVGL_DIR)/src/draw/*.c \
$(LVGL_DIR)/src/font/*.c \
syscalls.c display_client.c
3. .desktop 文件
[Desktop Entry]
Name=Text Editor
Exec=/bin/text_editor
Icon=/usr/share/icons/text_editor.png
Type=Application
Categories=Utility;TextEditor;
🧪 七、运行效果
启动 Text Editor:
- 显示 LVGL 渲染的 UI:
- 顶部标题 "MyOS Text Editor"
- 中央多行文本区域
-
底部状态栏 "Lines: 1 Characters: 0" - 左侧 "New"/"Open" 按钮
- 鼠标交互:
- 按钮悬停变色
- 点击按钮触发事件
- 在文本区域点击/拖拽选择文字
- 文本编辑:
- 输入文字实时更新状态栏
- 支持多行、退格、回车
- 光标闪烁(LVGL 内置)
✅ 专业级文本编辑器运行成功!
⚙️ 八、扩展方向
- 文件 I/O
- 实现
Open/Save功能(通过 ext2 系统调用) - 支持文件对话框(LVGL 内置)
- 实现
- 主题定制
- 修改 LVGL 颜色/字体/动画
- 实现暗色主题
- 高级编辑功能
- 查找/替换
- 语法高亮(需自定义绘制)
- 多窗口支持
- 每个文件一个 LVGL 屏幕
- 通过窗口管理器管理
💡 LVGL 的
lv_fs接口可直接对接你的 ext2 文件系统!
💬 写在最后
集成 LVGL 是开发效率的飞跃。
它让我们从 GUI 基础设施中解放,
专注于应用逻辑本身。
今天你创建的第一个 LVGL 文本编辑器,
正是无数嵌入式 GUI 应用的起点。
🌟 站在巨人的肩膀上,才能看得更远。
📬 动手挑战:
实现 "Save" 功能,将文本保存到 /home/user/document.txt。
欢迎在评论区分享你的 LVGL 应用截图!
👇 下一篇你想看:LVGL 文件浏览器,还是 多窗口文档编辑器?
#操作系统 #内核开发 #LVGL #GUI #文本编辑器 #嵌入式GUI #从零开始
📢 彩蛋:关注后回复关键词 "lvgl",获取:
- LVGL 移植模板(Display/Input Driver)
- 完整文本编辑器源码
- LVGL + MyOS 构建脚本