基础组件研究
Code地址:https://github.com/lvgl
中文参考文档(可能部分内容不匹配,仅参考):http://lvgl.100ask.net/8.2/index.html
官方API参考文档地址:https://docs.lvgl.io/master/intro/index.html
注意:LVGL 7.x版本与8.x版本差别很大,建议使用8.x版本
Windows 模拟器
Clone https://github.com/lvgl/lv_sim_visual_studio.git
- 查看依赖的lv_drivers和lvgl是否下载,地址
https://github.com/lvgl/lvgl https://github.com/lvgl/lv_drivers
- VS2019 打开 LVGL.Simulator.sln
- Rebuild & Run
入口程序 LVGL.Simulator.cpp, 需要按照自己的需求,释放对应的example code. UI大小默认800*480
/*
* PROJECT: LVGL PC Simulator using Visual Studio
* FILE: LVGL.Simulator.cpp
* PURPOSE: Implementation for LVGL ported to Windows Desktop
*
* LICENSE: The MIT License
*
* DEVELOPER: Mouri_Naruto (Mouri_Naruto AT Outlook.com)
*/
#include <Windows.h>
#include "resource.h"
#if _MSC_VER >= 1200
// Disable compilation warnings.
#pragma warning(push)
// nonstandard extension used : bit field types other than int
#pragma warning(disable:4214)
// 'conversion' conversion from 'type1' to 'type2', possible loss of data
#pragma warning(disable:4244)
#endif
#include "lvgl/lvgl.h"
#include "lvgl/examples/lv_examples.h"
#include "lvgl/demos/lv_demos.h"
#include "lv_drivers/win32drv/win32drv.h"
#if _MSC_VER >= 1200
// Restore compilation warnings.
#pragma warning(pop)
#endif
#include <stdio.h>
int main()
{
lv_init();
if (!lv_win32_init(
GetModuleHandleW(NULL),
SW_SHOW,
800,
480,
LoadIconW(GetModuleHandleW(NULL), MAKEINTRESOURCE(IDI_LVGL))))
{
return -1;
}
lv_win32_add_all_input_devices_to_group(NULL);
/*
* Demos, benchmarks, and tests.
*
* Uncomment any one (and only one) of the functions below to run that
* item.
*/
// ----------------------------------
// my freetype application
// ----------------------------------
///*Init freetype library
// *Cache max 64 faces and 1 size*/
//lv_freetype_init(64, 1, 0);
///*Create a font*/
//static lv_ft_info_t info;
//info.name = "./lvgl/src/extra/libs/freetype/arial.ttf";
//info.weight = 36;
//info.style = FT_FONT_STYLE_NORMAL;
//lv_ft_font_init(&info);
///*Create style with the new font*/
//static lv_style_t style;
//lv_style_init(&style);
//lv_style_set_text_font(&style, info.font);
///*Create a label with the new style*/
//lv_obj_t* label = lv_label_create(lv_scr_act());
//lv_obj_add_style(label, &style, 0);
//lv_label_set_text(label, "FreeType Arial Test");
// ----------------------------------
// my Win32 filesystem driver application
// ----------------------------------
/*::lv_fs_win32_init();
lv_fs_dir_t d;
if (lv_fs_dir_open(&d, "/") == LV_FS_RES_OK)
{
char b[MAX_PATH];
memset(b, 0, MAX_PATH);
while (lv_fs_dir_read(&d, b) == LV_FS_RES_OK)
{
printf("%s\n", b);
}
lv_fs_dir_close(&d);
}*/
// ----------------------------------
// Demos from lv_examples
// ----------------------------------
// lv_demo_widgets(); // ok
// lv_demo_benchmark();
// lv_demo_keypad_encoder(); // ok
// lv_demo_music(); // removed from repository
// lv_demo_printer(); // removed from repository
// lv_demo_stress(); // ok
// ----------------------------------
// LVGL examples
// ----------------------------------
/*
* There are many examples of individual widgets found under the
* lvgl\exampless directory. Here are a few sample test functions.
* Look in that directory to find all the rest.
*/
// lv_ex_get_started_1();
// lv_ex_get_started_2();
// lv_ex_get_started_3();
// lv_example_flex_1();
// lv_example_flex_2();
// lv_example_flex_3();
// lv_example_flex_4();
// lv_example_flex_5();
// lv_example_flex_6(); // ok
// lv_example_grid_1();
// lv_example_grid_2();
// lv_example_grid_3();
// lv_example_grid_4();
// lv_example_grid_5();
// lv_example_grid_6();
lv_port_disp_template();
// lv_port_fs_template();
// lv_port_indev_template();
// lv_example_scroll_1();
// lv_example_scroll_2();
// lv_example_scroll_3();
// lv_example_style_1();
// lv_example_style_2();
// lv_example_style_3();
// lv_example_style_4(); // ok
// lv_example_style_6(); // file has no source code
// lv_example_style_7();
// lv_example_style_8();
// lv_example_style_9();
// lv_example_style_10();
// lv_example_style_11(); // ok
// ----------------------------------
// LVGL widgets examples
// ----------------------------------
// lv_example_arc_1();
// lv_example_arc_2();
// lv_example_bar_1(); // ok
// lv_example_bar_2();
// lv_example_bar_3();
// lv_example_bar_4();
// lv_example_bar_5();
// lv_example_bar_6(); // issues
// lv_example_btn_1();
// lv_example_btn_2();
// lv_example_btn_3();
// lv_example_btnmatrix_1();
// lv_example_btnmatrix_2();
// lv_example_btnmatrix_3();
// lv_example_calendar_1();
// lv_example_canvas_1();
// lv_example_canvas_2();
// lv_example_chart_1(); // ok
// lv_example_chart_2(); // ok
// lv_example_chart_3(); // ok
// lv_example_chart_4(); // ok
// lv_example_chart_5(); // ok
// lv_example_chart_6(); // ok
// lv_example_checkbox_1();
// lv_example_colorwheel_1(); // ok
// lv_example_dropdown_1();
// lv_example_dropdown_2();
// lv_example_dropdown_3();
// lv_example_img_1();
// lv_example_img_2();
// lv_example_img_3();
// lv_example_img_4(); // ok
//lv_example_imgbtn_1();
// lv_example_keyboard_1(); // ok
// lv_example_label_1();
// lv_example_label_2(); // ok
// lv_example_led_1();
// lv_example_line_1();
// lv_example_list_1();
// lv_example_meter_1();
// lv_example_meter_2();
// lv_example_meter_3();
// lv_example_meter_4(); // ok
// lv_example_msgbox_1();
// lv_example_obj_1(); // ok
// lv_example_roller_1();
// lv_example_roller_2(); // ok
// lv_example_slider_1(); // ok
// lv_example_slider_2(); // issues
// lv_example_slider_3(); // issues
// lv_example_spinbox_1();
// lv_example_spinner_1(); // ok
// lv_example_switch_1(); // ok
// lv_example_table_1();
// lv_example_table_2(); // ok
// lv_example_tabview_1();
// lv_example_textarea_1(); // ok
// lv_example_textarea_2();
// lv_example_textarea_3(); // ok, but not all button have functions
// lv_example_tileview_1(); // ok
// lv_example_win_1(); // ok
// ----------------------------------
// Task handler loop
// ----------------------------------
while (!lv_win32_quit_signal)
{
lv_task_handler();
Sleep(1);
}
return 0;
}
单片机如何集成
- 使用git命令
git clone https://github.com/lvgl/lvgl.git
从 GitHub 下载或克隆库。 - 将
lvgl
文件夹复制到您的项目中。 - 将
lvgl/lv_conf_template.h
作为lv_conf.h
复制到lvgl
文件夹旁边,将其第一个的#if 0
更改为1
以使能文件的内容并修改设置LV_COLOR_DEPTH
宏。 - 在需要使用 LVGL 相关函数的文件中包含
lvgl/lvgl.h
。 - 在计时器或任务中每
x
毫秒调用一次lv_tick_inc(x)
(x
应该在 1 到 10 之间)。 LVGL 的内部时序需要它。或者,配置LV_TICK_CUSTOM
(参见lv_conf.h
),以便 LVGL 可以直接检索当前时间。 - 调用
lv_init()
(初始化lvgl库) - 创建一个绘制缓冲区:LVGL 将首先在此处渲染图形,并将渲染的图像发送到显示器。 缓冲区大小可以自由设置,但 1/10 屏幕大小是一个很好的起点。
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[DISP_HOR_RES * DISP_VER_RES / 10]; /*Declare a buffer for 1/10 screen size*/
lv_disp_draw_buf_init(&draw_buf, buf1, NULL, MY_DISP_HOR_RES * MY_DISP_VER_RES / 10); /*Initialize the display buffer.*/
- 实现并注册一个函数,该函数可以将渲染图像复制到显示区域:
lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
disp_drv.buffer = &draw_buf; /*Assign the buffer to the display*/
disp_drv.hor_res = MY_DISP_HOR_RES; /*Set the horizontal resolution of the display*/
disp_drv.hor_res = MY_DISP_VER_RES; /*Set the verizontal resolution of the display*/
lv_disp_drv_register(&disp_drv); /*Finally register the driver*/
void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
int32_t x, y;
/*It's a very slow but simple implementation.
*`set_pixel` needs to be written by you to a set pixel on the screen*/
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
set_pixel(x, y, *color_p);
color_p++;
}
}
lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/
}
- 实现并注册一个可以读取输入设备的函数。例如。对于触摸板:
lv_indev_drv_t indev_drv; /*Descriptor of a input device driver*/
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
lv_indev_drv_register(&indev_drv); /*Finally register the driver*/
bool my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data)
{
/*`touchpad_is_pressed` and `touchpad_get_xy` needs to be implemented by you*/
if(touchpad_is_pressed()) {
data->state = LV_INDEV_STATE_PRESSED;
touchpad_get_xy(&data->point.x, &data->point.y);
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
- 在主
while(1)
循环或操作系统任务中每隔几毫秒定期调用lv_timer_handler()
。 如果需要,它将重绘屏幕,处理输入设备,动画等。
基础概念
- 组织关系
LVGL从屏幕对象开始,一层层的父子关系传递下去,组成了组件树。
子项只有在父项上时可见,父项销毁,子项也会被删除掉。
如果父节点的位置发生变化,子节点将与父节点一起移动。 因此,所有位置都相对于父级。 - 屏幕
屏幕是没有父对象的特殊对象。所以它们可以像这样创建:lv_obj_t * scr1 = lv_obj_create(NULL);
屏幕是在当前选择的_默认显示_上创建的。 default display 是最后一个用lv_disp_drv_register
注册的显示,或者你可以使用lv_disp_set_default(disp)
明确地选择一个新的默认显示。
LVGL支持多个屏幕,所以支持多个根对象。lv_scr_act()
获取当前屏幕,lv_src_load(src1)
加载一个屏幕。lv_scr_load_anim
设置屏幕切换动画。 - Layers(层)
Screen有两个自动生成的层:顶层, 系统层
它们独立于屏幕,将显示在每个屏幕上。
顶层位于屏幕上的每个对象之上,系统层也位于顶层之上。 您可以自由地将任何弹出窗口添加到顶层。但是,系统层仅限于系统级事物(如:鼠标).lv_layer_top()
和lv_layer_sys()
函数分别返回指向顶层和系统层的指针。 - 常用函数
lv_obj_t* p = lv_<type>_create(parent);
创建一个UI对象。lv_obj_set_<parameter_name>(obj, <value>);
通用的设置对象属性方法。包含x,y,pos,width,height,size,....
lv_<widget_type>_set_<parameter_name>(obj, <value>);
针对个别UI有自己的特殊参数设定 - 事件 Event
LVGL中UI对象发生了变化,会触发一个event, 它包含点击、拖动、删除等。
一般通过lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED/LV_EVENT_ALL, NULL);
来设定。
在回调函数中,通过lv_event_code_t code = lv_event_get_code(e);
可以得到事件代码,通过lv_obj_t * obj = lv_event_get_target(e);
得到出发事件的对象。 - 部件 Parts
一个UI对象可能由一个或多个部分构建,成为部件。不同UI对象的部件数量是不同的。
如:按钮只有LV_PART_MAIN
, 滑块就有LV_PART_MAIN, LV_PART_INDICATOR, LV_PART_KNOB
三部分组成。
-
LV_PART_MAIN
类似矩形的背景 -
LV_PART_SCROLLBAR
滚动条 -
LV_PART_INDICATOR
指标,例如用于滑块、条、开关或复选框的勾选框 -
LV_PART_KNOB
像手柄一样可以抓取调整值 -
LV_PART_SELECTED
表示当前选择的选项或部分 -
LV_PART_ITEMS
如果小部件有多个相似的元素(例如表格单元格) -
LV_PART_TICKS
刻度上的刻度,例如对于图表或仪表 -
LV_PART_CURSOR
标记一个特定的地方,例如文本区域或图表的光标 -
LV_PART_CUSTOM_FIRST
可以从这里添加自定义部件。
- 状态 Status
每个UI部件都是很多状态的组合体,一般有如下状态:
-
LV_STATE_DEFAULT
正常,释放状态 -
LV_STATE_CHECKED
切换或选中状态 -
LV_STATE_FOCUSED
通过键盘或编码器聚焦或通过触摸板/鼠标点击 -
LV_STATE_FOCUS_KEY
通过键盘或编码器聚焦,但不通过触摸板/鼠标聚焦 -
LV_STATE_EDITED
由编码器编辑 -
LV_STATE_HOVERED
鼠标悬停(现在不支持) -
LV_STATE_PRESSED
被按下 -
LV_STATE_SCROLLED
正在滚动 -
LV_STATE_DISABLED
禁用
可以通过lv_obj_has_state(obj, LV_STATE_...)
来判断UI对象的是否有此状态。通过lv_obj_add_state/lv_obj_clear_state
添加删除状态。
- 样式 Style
样式lv_style_t
包含诸如背景颜色、边框宽度、字体等属性来描述对象的外观。
因为只有它们的指针保存在UI对象中,因此它们需要是静态的或全局的。并且使用前需要初始化lv_style_init(&style1)
.
不同的样式可以级联,即你可以对一个UI对象同时设置多个样式。
部分样式内容是可以继承的,如字体。
本地样式:只对某个对象有效的样式。lv_obj_set_style_bg_color(slider1, lv_color_hex(0x2080bb), LV_PART_INDICATOR | LV_STATE_PRESSED);
static lv_style_t style1;
lv_style_init(&style1);
lv_style_set_bg_color(&style1, lv_color_hex(0xa03080));
lv_style_set_border_width(&style1, 2));
lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR | LV_STATE_PRESSED); // 样式只设置 INDICATOR的Pressed状态。 0 = LV_PART_MAIN | LV_STATE_DEFAULT
- 主题 Themes
主题是对象的默认样式(即全局默认样式Style)。创建对象时,将自动应用来自主题的样式。
可以在lv_conf.h
中选择要使用的主题。 - 日志 Logging
LVGL 有内置的 Log 模块来通知用户库中发生的事情。
启用日志记录,请在lv_conf.h
中设置LV_USE_LOG 1
并将LV_LOG_LEVEL
设置为以下值之一:LV_LOG_LEVEL_TRACE/INFO/WARN/ERROR/USER/NONE
日志输出:通过LV_LOG_TRACE/INFO/WARN/ERROR/USER(text)
函数使用日志模块. - 如果系统支持
printf
,你只需要在lv_conf.h
中启用LV_LOG_PRINTF
就可以发送带有 printf 的日志。 - 如果不能使用
printf
或者想使用自定义函数来记录日志,可以使用lv_log_register_print_cb()
注册一个“记录器”回调。
void my_log_cb(const char * buf)
{
serial_send(buf, strlen(buf));
}
...
lv_log_register_print_cb(my_log_cb);
对象属性
与 LVGL 的许多其他部分类似,设置坐标的概念受到 CSS 的启发。绝不是标准的完整实现,而是实现了 CSS 的子集(有时会稍作调整)。 简而言之,这意味着:
- 设置的坐标(大小、位置、布局等)存储在样式中
- 支持最小宽度、最大宽度、最小高度、最大高度
- 有像素、百分比和“内容”单位。默认是像素
lv_obj_set_x(btn, 10)
,百分比设定lv_pct(50)
, 按内容LV_SIZE_CONTENT
- x=0; y=0 坐标表示父级的左上角加上左/上填充加上边框宽度
- 宽度/高度表示全尺寸,“内容区域”较小,填充和边框宽度
- 支持 flexbox 和网格布局的子集
带有 LV_OBJ_FLAG_HIDDEN
或 LV_OBJ_FLAG_FLOATING
的对象将被 LV_SIZE_CONTENT
计算忽略。
对象的“盒子”由以下部分构成:
- 轮廓(outline)绘制在边界框之外。
- 边界(bounding)框:绘制在边界(bounding)框内,元素的宽度/高度围起来的区域。
- 边框(border)宽度:边框的宽度。
- 填充(padding):对象两侧与其子对象之间的空间。
- 内容(content):如果边界框按边框宽度和填充的大小缩小,则显示其大小的内容区域。
注意:
- LVGL 不会立即重新计算所有坐标变化。这样做是为了提高性能。 相反,对象被标记为“脏”,并且在重绘屏幕之前 LVGL 检查是否有任何“脏”对象。
- 如果您需要获取对象的任何坐标并且坐标刚刚更改,则需要强制 LVGL 重新计算坐标。 为此调用
lv_obj_update_layout(obj)
。 - 如果你使用
lv_obj_set_x(obj, 20)
LVGL 将x=20
保存在对象的本地样式中。所以,如果对象的样式被删除,设置的坐标也将被删除。
对象的对齐:
- 默认的左上角更改定位, 更改默认方式
lv_obj_set_align(obj, align);
。 - 设置对齐方式
lv_obj_align(obj, align, x, y);
- 与其他对象对齐
lv_obj_align_to(obj_to_align, reference_obj, align, x, y);
- LV_ALIGN是在内部对齐,还可以在外部对齐LV_ALIGN_OUT
- 与
lv_obj_align()
不同,lv_obj_align_to()
无法重新对齐对象,如果其坐标或参考对象的坐标发生变化
风格样式转换 Translation:
如果想在按下按钮时将其向上移动一点,一般是设置两种style:
static lv_style_t style_normal;
lv_style_init(&style_normal);
lv_style_set_y(&style_normal, 100);
static lv_style_t style_pressed;
lv_style_init(&style_pressed);
lv_style_set_y(&style_pressed, 80);
lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);
lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);
lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT);
lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED);
但是这样style_normal和style_pressed里面y的参数是固定的,不好重用。所以可以考虑进行相对变换:
static lv_style_t style_normal;
lv_style_init(&style_normal);
lv_style_set_y(&style_normal, 100);
static lv_style_t style_pressed;
lv_style_init(&style_pressed);
lv_style_set_translate_y(&style_pressed, -20); // y = y - 20;
lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);
lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);
lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT);
lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED);
平移实际上移动了对象。
这意味着它使滚动条和 LV_SIZE_CONTENT 大小的对象对位置变化做出反应。即UI对象本身y左边发生了变化。
但是,并不是希望所有的变化都是改变原始的值,希望是临时的变化,可以考虑 转换 transformation:
static lv_style_t style_pressed;
lv_style_init(&style_pressed);
lv_style_set_transform_width(&style_pressed, 10);
lv_style_set_transform_height(&style_pressed, 10);
lv_obj_add_style(btn, &style_pressed, LV_STATE_PRESSED);
这样按钮按下时,长宽只是临时变大10px,随后自动恢复原始大小。
Layout
分为 Flexbox(弹性伸缩盒), Grid(网格).
有一些标志可用于对象以影响它们在布局中的行为:
-
LV_OBJ_FLAG_HIDDEN
隐藏对象从布局计算中被忽略。 -
LV_OBJ_FLAG_IGNORE_LAYOUT
该对象被布局简单地忽略。它的坐标可以照常设置。 -
LV_OBJ_FLAG_FLOATING
与LV_OBJ_FLAG_IGNORE_LAYOUT
相同,但带有LV_OBJ_FLAG_FLOATING
的对象将在LV_SIZE_CONTENT
计算中被忽略。
可以使用 lv_obj_add/clear_flag(obj, FLAG);
添加/删除这些标志
其他参考
- Style列表与解释 https://docs.lvgl.io/master/overview/style-props.html
pad_row/column 行/列元素之间的填充
bg_color 背景颜色,默认0xffffff
bg_opa 背景不透明度,0完全透明,255完全不透明。LV_OPA_10 表示10%. 默认0.
bg_grad_color 背景渐变色
bg_grad_dir 背景渐变色方向, LV_GRAD_DIR_NONE/HOR/VER
bg_main_stop 背景渐变色从哪里开始,0左上,255右下,128表示中心.默认值0
bg_grad_stop 类似main_stop但是默认值255
bg_grad 合并BG_GRAD_COLOR
BG_GRAD_DIR
BG_MAIN_STOP
BG_GRAD_STOP
。
bg_dither_mode 背景渐变的抖动模式LV_DITHER_NONE/ORDERED/ERR_DIFF
bg_img_src 背景图片,可以说文件指针或者路径、数组
bg_img_opa 背景图片透明度
bg_img_recolor 背景图片的混合颜色,默认0x000000
bg_img_recolor_opa 背景图片的混合颜色的强度,0表示不混合,255完全重新着色。支持LV_OPA_10
bg_img_tiled 背景图像平铺,默认false
img_opa/recolor/recolor_opa 前景图片的透明度和重着色
border_color 边框颜色,默认0x000000
border_opa 边框颜色的不透明度
border_width 边框宽度,单位像素,默认0
border_side 边框绘制哪一侧,支持OR操作。LV_BORDER_SIDE_NONE/TOP/BOTTOM/LEFT/RIGHT/INTERNAL``LV_BORDER_SIDE_TOP | LV_BORDER_SIDE_LEFT
border_post 是在子项绘制之后绘制边框? true/false
outline_width/color/opa/pad 外轮廓的宽度等
shadow_width/color/opa/ofs_x/ofs_y/spread 阴影的参数,偏移量,区域扩展
line_width/dash_width/dash_gap 线状结构的线宽和虚线参数
line_rounded 线端点的圆角
line_color/opa 线的颜色和不透明度
arc_width/rounded/color/opa/img_src 圆弧的宽度颜色等
text_color/opa/font/align 文本的颜色、字体、不透明度、对齐等
text_letter_space/line_space 文本的字母间距和行间距,单位像素
text_decor 文本的修饰,LV_TEXT_DECOR_NONE/UNDERLINE/STRIKETHROUGH
的组合
radius 圆角半径,单位像素。
clip_corner 裁剪圆角上的溢出内容,默认false
opa 按照这个值缩小所有子元素的不透明度。默认LV_OPA_COVER.
color_filter_dsc 将一种颜色混合到对象的所有颜色
color_filter_opa 颜色混合的强度
anim 动画模板,指向指针lv_anim_t
anim_time 动画持续时间,单位毫秒
anim_speed 动画速度,单位像素/秒
transition 过渡,lv_style_transition_dsc_t
blend_mode 如何将颜色混合到背景LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE/MULTIPLY
base_dir 设置对象的基本方向LV_BIDI_DIR_LTR/RTL/AUTO
- Scroll 滚动条,具体参考 https://docs.lvgl.io/master/overview/scroll.html
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_...)
设置对象的滚动条模式。
-
LV_SCROLLBAR_MODE_OFF
从不显示滚动条 -
LV_SCROLLBAR_MODE_ON
始终显示滚动条 -
LV_SCROLLBAR_MODE_ACTIVE
滚动对象时显示滚动条 -
LV_SCROLLBAR_MODE_AUTO
当内容大到可以滚动时显示滚动条
- Event 事件
任何自定义事件代码都可以通过以下方式注册uint32_t MY_EVENT_1 = lv_event_register_id();
手动将事件发送到对象,请使用。lv_event_send(obj, <EVENT_CODE> &some_data)
/*Simulate the press of the first button (indexes start from zero)*/
uint32_t btn_id = 0;
lv_event_send(mbox, LV_EVENT_VALUE_CHANGED, &btn_id);
LV_EVENT_REFRESH
是一个特殊事件,因为它旨在让用户通知对象自行刷新。一些例子:
- 通知标签根据一个或多个变量(例如当前时间)刷新其文本
- 语言更改时刷新标签
- 如果满足某些条件(例如,输入了正确的 PIN),则启用按钮
- 在超出限制时向对象添加/删除样式等
lv_event_t
是传递给事件回调的唯一参数,它包含有关事件的所有数据。可以从中获取以下值: -
lv_event_get_code(e)
获取事件代码 -
lv_event_get_current_target(e)
获取向其发送事件的对象。即正在调用其事件处理程序的对象。 -
lv_event_get_target(e)
获取最初触发事件的对象(启用不同的 Fromif事件冒泡)lv_event_get_target
-
lv_event_get_user_data(e)
获取作为最后一个参数传递的指针。lv_obj_add_event_cb
-
lv_event_get_param(e)
获取作为最后一个参数传递的参数lv_event_send
事件冒泡, 启用LV_OBJ_FLAG_EVENT_BUBBLE
的UI会所有事件也将发送到对象的父级lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE)
static void event_cb(lv_event_t * e)
{
/*The original target of the event. Can be the buttons or the container*/
lv_obj_t * target = lv_event_get_target(e);
/*The current target is always the container as the event is added to it*/
lv_obj_t * cont = lv_event_get_current_target(e);
/*If container was clicked do nothing*/
if(target == cont) return;
/*Make the clicked buttons red*/
lv_obj_set_style_bg_color(target, lv_palette_main(LV_PALETTE_RED), 0);
}
/**
* Demonstrate event bubbling
*/
void lv_example_event_3(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 290, 200);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW_WRAP);
uint32_t i;
for(i = 0; i < 30; i++) {
lv_obj_t * btn = lv_btn_create(cont);
lv_obj_set_size(btn, 80, 50);
lv_obj_add_flag(btn, LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text_fmt(label, "%"LV_PRIu32, i);
lv_obj_center(label);
}
lv_obj_add_event_cb(cont, event_cb, LV_EVENT_CLICKED, NULL);
}
- Input 输入设备 https://docs.lvgl.io/master/overview/indev.html
设置光标
lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv);
LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image source.*/
lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
lv_indev_set_cursor(mouse_indev, cursor_obj); /*Connect the image object to the driver*/
手势 LV_EVENT_GESTURE, 与触摸屏交互产生,一般不怎么用
键盘类设备
- 如果键盘类设备想要类似Tab捕获焦点,必须有一个组。需要将输入设备与组关联。
- 一个输入设备只能向一个组发送key事件,但一个组可以从多个输入设备接收数据。
- 交互式小部件(如按钮、复选框、滑块等)可以自动添加到默认组中。
只需创建一个组,然后使用lv_group_t * g = lv_group_create();``lv_group_set_default(g);
不要忘记将一个或多个输入设备分配给默认组。lv_indev_set_group(my_indev, g);
- 有一些预定义的键具有特殊含义:
- LV_KEY_NEXT专注于下一个对象
- LV_KEY_PREV专注于上一个对象
- LV_KEY_ENTER触发器等。事件
LV_EVENT_PRESSED/CLICKED/LONG_PRESSED
- LV_KEY_UP增加价值或向上移动
- LV_KEY_DOWN降低值或向下移动
- LV_KEY_RIGHT增加价值或向右移动
- LV_KEY_LEFT减小值或向左移动
- LV_KEY_ESC关闭或退出(例如,关闭下拉列表)
- LV_KEY_DEL删除(例如,文本区域中右侧的字符)
- LV_KEY_BACKSPACE删除左侧的字符(例如,在文本区域中)
- LV_KEY_HOME转到开头/顶部(例如,在文本区域中)
- LV_KEY_END转到末尾(例如,在文本区域中)
- 颜色
RGB颜色lv_color_t c = lv_color_make(red, green, blue); lv_color_t c = lv_color_hex(0x123456);
HSV颜色lv_color_t c = lv_color_hsv_to_rgb(h, s, v); lv_color_hsv_t c_hsv = lv_color_rgb_to_hsv(r, g, b); lv_color_hsv_t c_hsv = lv_color_to_hsv(color);
Palette 调色板,可以使用命名颜色以及4个更深的和5个更浅的变体
使用方式:lv_color_t c = lv_palette_main(LV_PALETTE_...); lv_palette_lighten(LV_PALETTE_..., v); lv_palette_darken(LV_PALETTE_..., v)
LV_PALETTE_RED
LV_PALETTE_PINK
LV_PALETTE_PURPLE
LV_PALETTE_DEEP_PURPLE
LV_PALETTE_INDIGO
LV_PALETTE_BLUE
LV_PALETTE_LIGHT_BLUE
LV_PALETTE_CYAN
LV_PALETTE_TEAL
LV_PALETTE_GREEN
LV_PALETTE_LIGHT_GREEN
LV_PALETTE_LIME
LV_PALETTE_YELLOW
LV_PALETTE_AMBER
LV_PALETTE_ORANGE
LV_PALETTE_DEEP_ORANGE
LV_PALETTE_BROWN
LV_PALETTE_BLUE_GREY
-
LV_PALETTE_GREY
颜色存储的变量:(配置默认颜色类型见 lv_conf.h的LV_COLOR_DEPTH) -
lv_color1_t
单色。为了兼容,还有 R、G、B 字段,但它们始终是相同的值(1 字节) -
lv_color8_t
用于存储 8 位颜色(1 字节)的 R(3 位)、G(3 位)、B(2 位)组件的结构 -
lv_color16_t
用于存储 R(5 位)、G(6 位)、B(5 位)组件的结构,用于存储 16 位颜色(2 字节) -
lv_color32_t
用于存储 R(8 位)、G(8 位)、B(8 位)组件的 24 位颜色(4 字节)的结构 -
lv_color_t
等于取决于配置的颜色深度设置lv_color1/8/16/24_t
-
lv_color_int_t
uint8_t
,或取决于颜色深度设置。用于从纯数字构建颜色数组。
- 字体
LVGL 支持UTF-8编码的 Unicode 字符。
字体具有bpp(每像素位数)属性。它显示使用多少位来描述字体中的像素。
可能的bpp值为 1、2、4 和 8(值越高意味着质量越好)。bpp属性还会影响存储字体所需的内存量。例如,bpp = 4使字体比bpp = 1 大近四倍。
普通字体:
- 包含所有 ASCII 字符、度数符号 (U+00B0)、项目符号 (U+2022) 和内置符号.
- 大小不同 LV_FONT_MONTSERRAT_12/14/16/18/20/22/24/26/28/30/32/34/36/38/40/42/44/46/48 特殊字体:
- LV_FONT_MONTSERRAT_12_SUBPX与普通 12 像素字体相同,但具有亚像素渲染
- LV_FONT_MONTSERRAT_28_COMPRESSED与普通 28 像素字体相同,但存储为 3 bpp 的压缩字体
- LV_FONT_DEJAVU_16_PERSIAN_HEBREW16 px 字体,正常范围 + 希伯来语、阿拉伯语、波斯语字母及其所有形式
-
LV_FONT_SIMSUN_16_CJK
16 px 字体,正常范围加上 1000 个最常见的 CJK 部首 -
LV_FONT_UNSCII_8
8 像素完美字体,仅包含 ASCII 字符 LV_FONT_UNSCII_16
16 像素的完美字体,只有 ASCII 字符
BPP=4的内置字体还包含了符号字体,可以单独、联合使用lv_label_set_text(my_label, LV_SYMBOL_OK); lv_label_set_text(my_label, LV_SYMBOL_OK "Apply");
- 输入法
默认的输入法不支持中文,需要单独使用中文字体和拼音输入法的组合。 - 图像
支持各种内置颜色格式:
- LV_IMG_CF_TRUE_COLOR只需存储 RGB 颜色(LVGL 配置的任何颜色深度)。
- LV_IMG_CF_TRUE_COLOR_ALPHA喜欢但它也为每个像素添加一个字母(透明度)字节。
LV_IMG_CF_TRUE_COLOR
- LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED喜欢但是如果一个像素有颜色(以_lv_conf.h_ 设置),它将是透明的。
LV_IMG_CF_TRUE_COLOR``LV_COLOR_TRANSP
- LV_IMG_CF_INDEXED_1/2/4/8位使用具有 2、4、16 或 256 种颜色的调色板,并以 1、2、4 或 8 位存储每个像素。
- **LV_IMG_CF_ALPHA_1/2/4/8BIT****仅存储 1、2、4 或 8 位的 Alpha 值。**像素采用颜色和设置的不透明度。源图像必须是 Alpha 通道。这非常适合类似于字体的位图,其中整个图像是一种可以更改的颜色。
style.img_recolor
使用图像数据的代码:
uint8_t my_img_data[] = {0x00, 0x01, 0x02, ...};
static lv_img_dsc_t my_img_dsc = {
.header.always_zero = 0,
.header.w = 80,
.header.h = 60,
.data_size = 80 * 60 * LV_COLOR_DEPTH / 8,
.header.cf = LV_IMG_CF_TRUE_COLOR, /*Set the color format*/
.data = my_img_data,
};
使用在线转换器得到的bin文件代码:
lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL);
/*From variable*/
LV_IMG_DECLARE(my_icon_dsc); // 声明图片
lv_img_set_src(icon, &my_icon_dsc);
/*From file*/
lv_img_set_src(icon, "S:my_icon.bin");
- 动画animations https://docs.lvgl.io/master/overview/animation.html
动画函数原型void func(void * var, lv_anim_var_t value);
一个全面的Demo:
/* INITIALIZE AN ANIMATION
*-----------------------*/
lv_anim_t a;
lv_anim_init(&a);
/* MANDATORY SETTINGS
*------------------*/
/*Set the "animator" function*/
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) lv_obj_set_x);
/*Set target of the animation*/
lv_anim_set_var(&a, obj);
/*Length of the animation [ms]*/
lv_anim_set_time(&a, duration);
/*Set start and end values. E.g. 0, 150*/
lv_anim_set_values(&a, start, end);
/* OPTIONAL SETTINGS
*------------------*/
/*Time to wait before starting the animation [ms]*/
lv_anim_set_delay(&a, delay);
/*Set path (curve). Default is linear*/
lv_anim_set_path(&a, lv_anim_path_ease_in);
/*Set a callback to indicate when the animation is ready (idle).*/
lv_anim_set_ready_cb(&a, ready_cb);
/*Set a callback to indicate when the animation is deleted (idle).*/
lv_anim_set_deleted_cb(&a, deleted_cb);
/*Set a callback to indicate when the animation is started (after delay).*/
lv_anim_set_start_cb(&a, start_cb);
/*When ready, play the animation backward with this duration. Default is 0 (disabled) [ms]*/
lv_anim_set_playback_time(&a, time);
/*Delay before playback. Default is 0 (disabled) [ms]*/
lv_anim_set_playback_delay(&a, delay);
/*Number of repetitions. Default is 1. LV_ANIM_REPEAT_INFINITE for infinite repetition*/
lv_anim_set_repeat_count(&a, cnt);
/*Delay before repeat. Default is 0 (disabled) [ms]*/
lv_anim_set_repeat_delay(&a, delay);
/*true (default): apply the start value immediately, false: apply start value after delay when the anim. really starts. */
lv_anim_set_early_apply(&a, true/false);
/* START THE ANIMATION
*------------------*/
lv_anim_start(&a); /*Start the animation*/
基础内容到此结束,其他内容参考官方文档。
后续针对控件和使用组合进行单独实例学习。