4、LVGL基础控件(上):标签(Label)、按钮(Button)、文本框(Text Area)
好,咱们今天来聊聊LVGL里最常用的三个基础控件。说实话,这三个控件你玩熟了,嵌入式UI的底子就算打牢了。我刚开始用LVGL做项目时,就是靠这三个控件撑起了一个完整的设置界面。你想想看,一个产品界面里,无非就是显示文字、点击按钮、输入内容这三件事。
4.1 标签(Label)—— 最朴素的文字显示
标签控件,说白了就是用来显示文本的。它不像文本框那样可以编辑,就是单纯地展示信息。嗯,这里要注意:别看它简单,用好了能省不少事。
4.1.1 创建与基本设置
/* 创建一个标签 */
lv_obj_t *label = lv_label_create(lv_scr_act());
/* 设置文本内容 */
lv_label_set_text(label, "Hello, RT-Thread!");
/* 设置文本对齐方式 */
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); /* 自动换行 */
lv_obj_set_width(label, 150); /* 设置宽度 */
lv_label_set_text(label, "这是一段较长的文本,会自动换行显示");
我个人习惯在创建标签后,先设置好宽度和对齐模式。为什么?因为我在项目里吃过亏——文本长了直接溢出屏幕,调试了半天才发现是没设换行模式。
4.1.2 文本样式与颜色
标签的样式修改,主要通过样式API来实现。我建议你养成一个习惯:所有样式修改都集中放在初始化函数里,别散落在各处。
/* 创建样式 */
static lv_style_t style_label;
lv_style_init(&style_label);
lv_style_set_text_color(&style_label, lv_color_hex(0x2196F3)); /* 蓝色 */
lv_style_set_text_font(&style_label, &lv_font_montserrat_20); /* 字体大小 */
lv_style_set_text_letter_space(&style_label, 2); /* 字间距 */
/* 应用样式 */
lv_obj_add_style(label, &style_label, 0);
lv_font_simsun_16_cjk 这个字体,覆盖常用汉字。
4.1.3 动态更新文本
实际项目中,标签内容经常需要动态更新。比如显示传感器数值、系统状态等。这里有个坑,我踩过:
/* 错误做法:直接赋值字符串指针 */
char *buffer = "温度: 25°C";
lv_label_set_text(label, buffer); /* 如果buffer是局部变量,释放后指针悬空! */
/* 正确做法:使用格式化函数 */
lv_label_set_text_fmt(label, "温度: %d°C", temperature);
我曾经在项目里用第一种方式,结果界面偶尔显示乱码。查了两天才发现是局部变量被释放了。从那以后,我只要涉及动态文本,一律用 lv_label_set_text_fmt。
4.2 按钮(Button)—— 交互的核心
按钮是用户与系统交互最直接的方式。LVGL的按钮控件其实是一个容器,你可以在里面放标签、图标等子对象。
4.2.1 创建与事件绑定
/* 创建按钮 */
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 120, 50);
lv_obj_center(btn);
/* 在按钮上添加标签 */
lv_obj_t *btn_label = lv_label_create(btn);
lv_label_set_text(btn_label, "确认");
lv_obj_center(btn_label);
/* 绑定点击事件 */
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL);
/* 事件回调函数 */
static void btn_event_cb(lv_event_t *e)
{
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
LV_LOG_USER("按钮被点击了!");
/* 在这里处理点击逻辑 */
}
}
4.2.2 按钮状态与样式
按钮有几种状态:默认、按下、禁用、聚焦等。你可以为每种状态设置不同的样式,让交互反馈更直观。
/* 定义不同状态的样式 */
static lv_style_t style_btn_default;
static lv_style_t style_btn_pressed;
static lv_style_t style_btn_disabled;
/* 默认状态:蓝色背景 */
lv_style_init(&style_btn_default);
lv_style_set_bg_color(&style_btn_default, lv_color_hex(0x2196F3));
lv_style_set_radius(&style_btn_default, 8);
/* 按下状态:深蓝色背景 */
lv_style_init(&style_btn_pressed);
lv_style_set_bg_color(&style_btn_pressed, lv_color_hex(0x1565C0));
/* 禁用状态:灰色背景 */
lv_style_init(&style_btn_disabled);
lv_style_set_bg_color(&style_btn_disabled, lv_color_hex(0x9E9E9E));
/* 应用样式到不同状态 */
lv_obj_add_style(btn, &style_btn_default, 0);
lv_obj_add_style(btn, &style_btn_pressed, LV_STATE_PRESSED);
lv_obj_add_style(btn, &style_btn_disabled, LV_STATE_DISABLED);
你想想看,用户按下按钮时,如果界面没有任何视觉反馈,他会怀疑自己到底按没按到。所以,我建议你至少给按钮设置按下和默认两种状态的样式差异。
4.2.3 按钮的启用与禁用
/* 禁用按钮 */
lv_obj_add_state(btn, LV_STATE_DISABLED);
/* 启用按钮 */
lv_obj_clear_state(btn, LV_STATE_DISABLED);
/* 检查按钮是否可用 */
if(lv_obj_has_state(btn, LV_STATE_DISABLED)) {
LV_LOG_USER("按钮当前不可用");
}
4.3 文本框(Text Area)—— 用户输入的门户
文本框允许用户输入和编辑文本。在嵌入式设备上,它通常配合键盘或触摸屏使用。说实话,文本框是这三个控件里最容易出问题的,因为涉及输入法、光标管理、文本长度限制等。
4.3.1 创建与基本配置
/* 创建文本框 */
lv_obj_t *ta = lv_textarea_create(lv_scr_act());
lv_obj_set_size(ta, 200, 100);
lv_obj_align(ta, LV_ALIGN_CENTER, 0, 0);
/* 设置占位文本 */
lv_textarea_set_placeholder_text(ta, "请输入内容...");
/* 设置最大字符数 */
lv_textarea_set_max_length(ta, 20);
/* 启用密码模式(显示为星号) */
lv_textarea_set_password_mode(ta, true);
/* 设置单行模式 */
lv_textarea_set_one_line(ta, true);
4.3.2 文本内容操作
/* 获取文本内容 */
const char *text = lv_textarea_get_text(ta);
/* 清空内容 */
lv_textarea_set_text(ta, "");
/* 在光标位置插入文本 */
lv_textarea_add_text(ta, "新插入的文本");
/* 删除光标前的字符 */
lv_textarea_del_char(ta);
/* 选中所有文本 */
lv_textarea_set_cursor_pos(ta, 0); /* 光标移到开头 */
lv_textarea_set_text_sel_start(ta, 0);
lv_textarea_set_text_sel_end(ta, strlen(lv_textarea_get_text(ta)));
4.3.3 事件处理与输入法配合
/* 监听文本变化事件 */
lv_obj_add_event_cb(ta, ta_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
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);
LV_LOG_USER("输入内容: %s", txt);
/* 实时校验输入内容 */
if(strlen(txt) > 10) {
lv_textarea_set_text(ta, txt); /* 截断处理 */
LV_LOG_USER("输入超长,已截断");
}
}
}
/* 配合键盘输入 */
void keyboard_input_handler(uint32_t key)
{
/* 假设key是ASCII码 */
char buf[2] = {0};
buf[0] = (char)key;
lv_textarea_add_text(ta, buf);
}
我记得有一次做工业设备界面,用户需要输入设备序列号。文本框默认支持全键盘输入,但客户要求只允许输入数字和大写字母。我就在事件回调里做了字符过滤,把非法字符直接丢弃。嗯,这个做法后来成了我们团队的通用方案。
4.3.4 光标与选中样式
/* 自定义光标颜色 */
static lv_style_t style_cursor;
lv_style_init(&style_cursor);
lv_style_set_bg_color(&style_cursor, lv_color_hex(0xFF0000)); /* 红色光标 */
lv_style_set_bg_opa(&style_cursor, LV_OPA_COVER);
/* 应用到文本框 */
lv_obj_add_style(ta, &style_cursor, LV_STATE_FOCUSED | LV_STATE_CURSOR);
/* 设置选中文本的背景色 */
static lv_style_t style_sel;
lv_style_init(&style_sel);
lv_style_set_bg_color(&style_sel, lv_color_hex(0x2196F3));
lv_obj_add_style(ta, &style_sel, LV_STATE_FOCUSED | LV_STATE_SELECTED);
4.4 三个控件的协同使用
实际项目中,这三个控件经常一起出现。比如一个登录界面:标签显示提示文字,文本框输入用户名和密码,按钮执行登录操作。我建议你设计界面时,先画个草图,规划好每个控件的位置和交互逻辑。
/* 一个简单的登录界面示例 */
void login_screen_create(void)
{
/* 标题标签 */
lv_obj_t *title = lv_label_create(lv_scr_act());
lv_label_set_text(title, "用户登录");
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 20);
/* 用户名输入框 */
lv_obj_t *ta_user = lv_textarea_create(lv_scr_act());
lv_obj_set_size(ta_user, 250, 40);
lv_obj_align(ta_user, LV_ALIGN_CENTER, 0, -30);
lv_textarea_set_placeholder_text(ta_user, "请输入用户名");
lv_textarea_set_one_line(ta_user, true);
/* 密码输入框 */
lv_obj_t *ta_pwd = lv_textarea_create(lv_scr_act());
lv_obj_set_size(ta_pwd, 250, 40);
lv_obj_align(ta_pwd, LV_ALIGN_CENTER, 0, 30);
lv_textarea_set_placeholder_text(ta_pwd, "请输入密码");
lv_textarea_set_password_mode(ta_pwd, true);
lv_textarea_set_one_line(ta_pwd, true);
/* 登录按钮 */
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 120, 45);
lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -40);
lv_obj_t *btn_label = lv_label_create(btn);
lv_label_set_text(btn_label, "登录");
lv_obj_center(btn_label);
/* 绑定登录事件 */
lv_obj_add_event_cb(btn, login_btn_cb, LV_EVENT_CLICKED, NULL);
}
好了,这一章的内容就到这里。标签、按钮、文本框这三个控件,你花点时间亲手敲一遍代码,跑几个示例,很快就能上手。下一章我们继续聊LVGL的高级控件,到时候会更有意思。