lvgl入门学习第三篇lvgl部件

一、标签(lv_label)

标签是用来显示文本的基本对象类型

在盒子模型里面,标签的组成包括:

  • LV_PART_MAIN 矩形部分(盒子区域)。 填充值可用于在文本和背景之间添加空间。
  • LV_PART_SCROLLBAR 当要展示的文本大于部件的大小时,显示的滚动条部分
  • LV_PART_SELECTED 选中文本时,突出显示的部分。label只能使用 text_color 和 bg_color 样式属性。

创建标签:lv_obj_t * label = lv_label_create(parent);

1.1 设置显示文本

创建了标签部件之后我们就可以设置文本来显示。

  • 直接设置要显示的文本:lv_label_set_text(label, "New text");
  • 格式化给定要显示的文本:lv_label_set_text_fmt(label, “%s: %d”, “Value”, 15);
  • 文本不存储在动态内存中,而是直接使用给定的缓冲区:lv_label_set_text_static(label, "New text");
  • 在label换行,像printf函数那样使用 \n 即可:lv_label_set_text(label, " line1\nline2\n\nline4 ");

1.2 大小

  • 默认情况标签的大小会自动拓展成和文本一样的大小(LV_SIZE_CONTENT),也可以设置宽高:lv_obj_set_size lv_obj_set_width lv_obj_set_height
  • 这样就可能出现文本的宽度或高度大小与label不一样的情况,需要做一些调整,下面是几种模式
LV_LABEL_LONG_WRAP 如果有多个换行,并且如果高度为LV_SIZE_CONTENT,那么高度会根据文本换行被自动扩展;否则文本将被剪掉。(默认设置)
LV_LABEL_LONG_DOT 如果文本太长,就保持大小并在末尾写3个点。
LV_LABEL_LONG_SCROLL 如果文本比标签宽(太长),则可以水平来回滚动显示它。如果它很高(多个\n换行),可以垂直滚动。只滚动一个方向,水平滚动的优先级更高。LV_LABEL_LONG_SCROLL_CIRCULAR 如果文本比标签宽,则水平滚动它。如果它更高,就垂直滚动。只滚动一个方向,水平滚动的优先级更高。
LV_LABEL_LONG_CLIP 剪掉超出标签范围外的文本部分。
可以使用 lv_label_set_long_mode(label, LV_LABEL_LONG_...) 指定模式。
  • 注意:
    1、LV_LABEL_LONG_DOT 是直接操作文本缓冲区以添加/删除点
    2、使用 lv_label_set_text 和 lv_label_set_text_fmt 会分配一个单独的缓冲区,不会出问题。
    3、使用 lv_label_set_text_static 时我们传递给它的缓冲区必须是可写的。
    image

1.3 文本着色

对要显示的文本重新着色,可以通过样式来上色,例如:lv_style_set_text_color(&style_obj, lv_color_hex(0xf7b37b));
lv_obj_set_style_text_color(label, lv_color_hex(0xf7b37b), 0);
也可以让文本某些部分重新着色,例如:
lv_label_set_recolor(label1, true);
lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label);

1.4 文本选择

  • 如果在 lv_conf.h 中打开了 LV_LABEL_TEXT_SELECTION (默认开启),就可以选择部分文本。这个和我们在PC用鼠标选中文本类似。但是这个效果只能在文本框(lv_textarea)中实现。Label只能事先手动选择指定范围的文本
    lv_label_set_text_sel_start(label, 1);
    lv_label_set_text_sel_end(label, 6);

  • 注意,这里的第一个字符从1开始算,而不是0

1.5 显示图标

LVGL内置了一些图标,它们是全局变量,可以直接使用
image

用法(LV_SYMBOL_...):

lv_label_set_text(my_label, LV_SYMBOL_OK);	// 直接显示图标
lv_label_set_text(my_label, LV_SYMBOL_OK “Apply”);	 // 图标与字符串一起使用
lv_label_set_text(my_label, LV_SYMBOL_OK LV_SYMBOL_WIFI LV_SYMBOL_PLAY); // 多个图标一起使用

1.6 事件处理

Label默认不接收输入事件,如果想设置输入类型的样式或者事件会无法生效需要打开 LV_OBJ_FLAG_CLICKABLE, 示例:lv_obj_add_flag(label, LV_OBJ_FLAG_CLICKABLE); // 使输入设备可点击对象

1.7 显示中文

  • LVGL内置有一个中文字库 CJK字库 ,这个字库在 lv_conf.h中定义为:LV_FONT_SIMSUN_16_CJK
  • 在lvgl中使用显示自己的中文字库,需要用到两个东西:字体文件和字体转换器
  • 字体文件使用开源的字体或者自己制作出来,准备好了字体文件之后使用字体转换器即可转换成可以在lvgl上使用的字体格式。开源字体获取页面:http://lvgl.100ask.net/8.1/tools/fonts-zh-source.html
  • 准备好字体文件之后就可以通过lvgl官方提供的字体转换器,提取转换你想要的字体,LVGL官方在线字体转换器页面:https://lvgl.io/tools/fontconverter

1.8 如何使用字体转换器?

  1. 为要输出字体命名。例如“font_source_han_sans_bold_20”
  2. 以 px为单位指定高度(字体大小)
  3. 设置bpp (bit-per-piel)。值越高,字体越平滑(抗锯齿)
  4. 选择TTF 或 WOFF 格式字体文件
  5. 设置要包含在字体中的Unicode 字符范围或在符号字段中列出字符
  6. 可以同时选择多个字体文件转换,并为其指定范围和/或符号。这些字符将被合并转换到同一个文件中。
  7. 单击转换按钮以下载转换出来的 font_source_han_sans_bold_20.c 文件。
    image

1.9 如何在 LVGL 中使用生成的字体?

  1. 将结果 C 文件复制到LVGL 项目中,并包含到项目;
  2. 在项目应用程序的 C 文件中,将字体声明为:extern lv_font_t my_font_name; 或:LV_FONT_DECLARE(my_font_name);
  3. 在样式中设置字体:
    lv_style_set_text_font(&style_obj, &my_font_name); // 普通(共享)样式
    lv_obj_set_style_text_font(label, &my_font_name, 0); // 私有(本地)样式
  4. unicode 是统一所有语言的一套编码。
  5. utf-8是基于unicode编码的一种节约字节的编码。

二、按钮(lv_btn)

  • 按钮是和基础对象最像的部件。与基础对象相比,按钮没有新的功能,只是默认的样式和基础对象不一样。
  • 默认情况,按钮和基础对象的不同点:
    不可滚动
    添加到默认组(可修改为给其他输入设备控制用,比如按键)
    高度和宽度默认为 LV_SIZE_CONTENT
  • 创建按键的方法:lv_obj_t * btn = lv_btn_create(parent);

为什么按钮和基础对象的默认样式不一样?
他们的创建接口都是一样的,是在什么时候、哪里决定了他们不一样的样式呢?
这要从lvgl默认的主题样式说起。

默认主题的初始化和应用过程:
lv_disp_drv_register
	lv_theme_default_init
		style_init
		theme.apply_cb = theme_apply;
-----------------------------------------------
lv_xxx_create
	lv_obj_class_init_obj
		lv_theme_apply
			apply_theme(th, obj);
			

2.1 部分和样式

  • 按钮的组成部分和基础对象一样,只有一个空空的盒子(盒子模型)。
  • 按钮的部分(Part)只有下面这个:
    LV_PART_MAIN 按钮的背景
  • 样式修改示例:
    lv_obj_set_style_<property_name>(obj, <value>, <selector>);// 本地(私有)样式
    lv_obj_add_style(obj, &style, <selector>) // 普通(共享)样式
    所以修改样式的时候我们修改部分(Part)的时候只有 LV_PART_MAIN 可以生效;状态部分和前面说的样式状态(States)都可以用

2.2 事件

事件可以像前面说的事件处理部分使用,但注意如下:
打开 LV_OBJ_FLAG_CHECKABLE ,当对象被点击时有选中切换(Toggle)状态的效果,并且可以在 LV_EVENT_VALUE_CHANGED 事件类型中处理事件比如:lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);

2.3 按键控制

总的来看,按钮是用来按的(单击、按下或不按下),所以我们用物理按键控制的时候只需要 LV_KEY_ENTER 就可以控制按钮
并且LV_KEY_ENTER 可以触发 LV_EVENT_PRESSED/PRESSING/RELEASED 等事件类型

三、使用物理按键代替触摸(groups)

3.1 组(groups)

  • 在LVGL中我们可以使用键盘或编码器替换触摸板或鼠标控制。它的工作原理类似于 PC 上的 TAB 键,用于选择应用程序或网页中的元素。
  • 首先将要用键盘或编码器控制的部件添加到组有的部件在创建时会加入到默认组
  • 在每个组中,同时只有一个对象聚焦并接收按键或编码器动作
  • 将输入设备与组关联。一个输入设备只能将按键发送给一组,反过来一组可以从多个输入设备接收数据。
  • 5种输入设备类型:
    LV_INDEV_TYPE_NONE 不使用输入设备(未初始化状态)
    LV_INDEV_TYPE_POINTER 触摸板、鼠标、外接按钮
    LV_INDEV_TYPE_KEYPAD 键盘
    LV_INDEV_TYPE_BUTTON 分配给屏幕特定点的外部(硬件按钮)
    LV_INDEV_TYPE_ENCODER 只有左、右和按下三个按键的编码器(比如鼠标中间的滚轮)

3.2 自定义组创建过程

  1. 首先创建一个 组(Groups) : lv_group_t * g = lv_group_create();
  2. 然后将一个对象添加到 组(Groups) 中: lv_group_add_obj(g, obj);
  3. 最后要将组(Groups)与输入设备相关联: lv_indev_set_group(indev, g);其中 indev 是 lv_indev_drv_register(); 的返回值

3.3 使用默认组

在lvgl中有些部件,在创建的时候加入到默认组中,但是默认组变量lvgl并没有帮我们初始化,需要在创建部件之前初始化才能使用默认组,对于创建时添加到默认的部件我们可以跳过lv_group_add_obj
lv_group_t * g = lv_group_create(); // 创建一个组
lv_group_set_default(g); // 设置为默认组
lv_indev_set_group(indev, g); // 将组和输入设备相关联

3.4 预定义按键

有一些预定义的键具有特殊含义:
image

3.5 必须的按键

  • 最重要且建议必要的按键是:

    • LV_KEY_NEXT/PREV
    • LV_KEY_ENTER
    • LV_KEY_UP/DOWN/LEFT/RIGHT
  • 在回调函数 read_cb 中,应该优先考虑将现有的键对应转换为上面这些键,以便能在组中导航并与所选对象进行交互。

  • 一般来说,只使用 LV_KEY_LEFT/RIGHT 就足够,因为大多数对象都可以通过它们被完全控制。

  • 对于编码器,默认只使用 LV_KEY_LEFT、LV_KEY_RIGHT 和 LV_KEY_ENTER

3.6 编辑(edit)和导航(navigate)模式

  • 编码器的按键有限,所以在各个对象之间进行导航就不方便了,lvgl分两种模式:编辑和导航模式
  • 导航模式下,编码器的 LV_KEY_LEFT/RIGHT 被转换为 LV_KEY_NEXT/PREV,可以通过转动编码器来选择下一个或上一个对象。
  • 如果需要修改对象的值,比如有个滑杆(lv_slider)代表音量或亮度,通过按下LV_KEY_ENTER 将模式切换为编辑模式,这样我们可以通过转动编码器来修改滑杆的值。然后根据对象的类型,短按或长按 LV_KEY_ENTER 切换为导航模式(离开编辑模式)。

3.7 默认组(Default group)

  • 交互式小部件 - 例如按钮、复选框、滑块等,在创建时会自动添加到默认组。默认组是:
  • 我们可以修改默认组为自己定义的:
    lv_group_t * g = lv_group_create(); // 创建组
    lv_group_set_default(g); // 设置默认组
    lv_indev_set_group(my_indev, g); //将输入设备分配到默认组。

3.8 风格样式

  • 通过触摸板点击选中对象或通过编码器或键盘聚焦对象,对象的状态会变为 LV_STATE_FOCUSED
  • 如果对象进入编辑模式,对象将进入 LV_STATE_FOCUSED | LV_STATE_EDITED 状态
  • 所以,可以根据上面两点,为对象设置被选中或聚焦或编辑时的样式

3.9 按键控制的初始化、工作流程和使用

lv_init
	_lv_group_init

lv_indev_drv_register
	lv_timer_create(lv_indev_read_timer_cb, LV_INDEV_DEF_READ_PERIOD, indev);

lv_indev_read_timer_cb
	_lv_indev_read(indev_act, &data); 	// 读取按键数据
		indev->driver->read_cb(indev->driver, data);
	indev_keypad_proc
		lv_group_send_data(g, LV_KEY_...);
			lv_event_send(act, LV_EVENT_KEY, &c);       // 发送处理按键事件,传递的参数是具体哪个按键	
		lv_event_send(indev_obj_act, LV_EVENT_..., indev_act);  // 模拟对对象的操作,比如按下事件
-----------------------------------------------
lv_xxx_create
	lv_obj_class_init_obj
		lv_group_add_obj

3.10 基础对象的作用

  • 基础对象是所有部件(对象)的基石,基础对象将所有对象的共性抽象出来
  • 使用物理按键或触摸的时候,为什么对象知道自己被聚焦(选中)并且做出回应的呢?
    其实这些基础对象都已经做好了,后面创建的对象直接使用即可。

四、开关(lv_switch)

  • 开关的功能类似于按钮,也可以用来打开和关闭某些东西。
  • 创建开关的方法:lv_obj_t * sw = lv_switch_create(parent);

4.1 零件和样式

开关包括以下3个零件:

  • LV_PART_MAIN 背景。 修改其 padding 会让下面的(指示器)在相应方向上的大小发生变化。
  • LV_PART_INDICATOR 显示开关状态的指示器。
  • LV_PART_KNOB 在指标左侧或右侧的旋钮。 默认情况下,旋钮是圆形的,边长等于滑块的较小边。 可以修改 padding 值使旋钮变大,填充值可以是不对称的。
示例:
// 修改开关背景部分的颜色
lv_obj_set_style_bg_color(sw, lv_color_hex(0xc43e1c), LV_PART_MAIN);
// 修改 pad,改变指示器在相应方向上的大小
lv_obj_set_style_pad_left(sw, 5, LV_PART_MAIN);     // lv_obj_set_style_pad...
// 修改开关状态指示器部分,关闭状态时的背景颜色
lv_obj_set_style_bg_opa(sw, 100, LV_PART_INDICATOR);
lv_obj_set_style_bg_color(sw, lv_color_hex(0xc43e1c), LV_PART_INDICATOR);
// 修改开关状态指示器部分,打开状态时的背景颜色
lv_obj_set_style_bg_color(sw, lv_color_hex(0x7719aa), LV_PART_INDICATOR | LV_STATE_CHECKED);
// 修改开关旋钮部分的颜色
lv_obj_set_style_bg_color(sw, lv_color_hex(0xc43e1c), LV_PART_KNOB);

4.2 用法

  • 开关被打开时,开关的状态会变为 LV_STATE_CHECKED 。我们可以通过下面这两个接口获取开关当前的状态:
    lv_obj_has_state(switch, LV_STATE_CHECKED); // 返回 bool 类型, 开-1 ; 关-2
    lv_obj_get_state(switch); // 返回枚举类型: LV_STATE_...
  • 一般我们通过触摸或按键控制让开关 打开/关闭,还可以通过下面这个接口来主动 打开/关闭
    lv_obj_add_state(switch, LV_STATE_CHECKED); // 开
    lv_obj_clear_state(switch, LV_STATE_CHECKED); // 关
  • 可以通过下面的接口让按钮处于不可更改状态
    lv_obj_add_state(sw, LV_STATE_DISABLED); // 当前状态是关,并且不可更改
    lv_obj_add_state(sw, LV_STATE_CHECKED | LV_STATE_DISABLED); // 当前状态是开,并且不可更改
  • 让按钮恢复可以更改的状态,只要将 LV_STATE_DISABLED 清除即可:
    lv_obj_clear_state(switch, LV_STATE_ DISABLED); // 清除禁用状态,按钮可正常使用

4.3 事件处理

正常情况下,当开关被点击并且状态发生改变时,触发 LV_EVENT_VALUE_CHANGED 事件类型。也就是说可以在 LV_EVENT_VALUE_CHANGED 事件类型中处理事件,比如: lv_obj_add_event_cb(switch, event_handler, LV_EVENT_VALUE_CHANGED, NULL);

4.4 按键控制

LV_KEY_UP/RIGHT 开
LV_KEY_DOWN/LEFT 关
LV_KEY_ENTER 切换开关

posted @ 2023-03-12 11:40  登云上人间  阅读(5963)  评论(0编辑  收藏  举报