Display
每一个物理显示设备都有一个Display(lv_display)
lvgl初始化一个物理显示设备需要进行以下操作:
- 为这个物理显示设备创建一个lv_display_t对象,并设置物理设备的宽高
- 为这个对象提供绘图函数(硬件驱动)
- 分配draw_buffers。把这个buffer当成lvgl的草稿纸,lvgl写完草稿了,才会写到屏幕上。使用lvgl画图,控件变化等功能,比如填充(0,0,320,240)这个区域lvgl会现在这个buffer中完成绘制,再调用绘图函数将buffer里的数据同步到显示屏。注意:buffer可能很小,比如才320*10,那么这个buffer,需要调用240/10=24次绘图函数。
static void init_lvgl_buf(void)
{
/*Create a display buffer*/
static lv_disp_draw_buf_t disp_buf1;//定义一个显示绘图缓冲区结构体,用于管理 LVGL 的“草稿纸”。
static lv_color_t buf1_1[SDL_HOR_RES * 100];//分配一块内存作为缓冲区
lv_disp_draw_buf_init(&disp_buf1, buf1_1, NULL, SDL_HOR_RES * 100);//初始化缓冲区结构体
/*创建 lv_disp_drv_t驱动描述符 */
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
/* 给驱动描述符对象分配内存,设置Display宽高,提供绘图函数*/
disp_drv.draw_buf = &disp_buf1;
disp_drv.flush_cb = sdl_display_flush;
disp_drv.hor_res = SDL_HOR_RES;
disp_drv.ver_res = SDL_VER_RES;
/*创建Display对象,会根据前面的驱动描述符对象中的内容创建*/
lv_disp_t *disp = lv_disp_drv_register(&disp_drv);
}
lv_disp_drv_register做了什么
为什么**lv_scr_act()**能拿到默认显示屏的widgets根节点?
LVGL 中,显示设备通过全局链表和默认指针来管理多个显示屏。
- 全局静态变量:在文件作用域定义链表头(
_lv_ll_t)和全局disp_default指针,提供模块内部的“上下文”。必然有一个变量存储lv_disp_t - 通用链表(
_lv_ll_t):LVGL 实现了一个轻量级双向链表,可容纳任意类型的节点,避免为每种对象重写链表操作。 - 动态内存分配:为每个显示设备分配独立的
lv_disp_t对象,插入链表后统一管理。
- 分配并初始化
lv_disp_t对象- 存储显示驱动参数(分辨率、flush 回调、绘图缓冲区等)。
- 将该对象挂入全局显示链表,若为第一个显示设备则设为默认显示。
- 创建两个屏幕对象(
lv_obj_t)- 活动屏幕(
act_scr):当前可见的主屏幕。 - 上一个屏幕(
prev_scr):用于屏幕切换动画的备用屏幕(初始与act_scr相同或为NULL)。
- 活动屏幕(
- 配置屏幕对象的基本属性
- 设置屏幕尺寸为显示设备的
hor_res × ver_res。 - 清除可滚动标志(屏幕本身不可滚动)。
- 标记对象类型为
LV_OBJ_CLASS_SCREEN,使其成为所有其他控件的根容器。 - 将屏幕的
parent设为NULL(顶级对象)。
- 设置屏幕尺寸为显示设备的
- 将屏幕与显示设备关联
disp->act_scr = new_scr,disp->prev_scr = NULL(或new_scr)。- 设置屏幕的
disp指针指向当前显示设备。
- 触发默认主题/样式的加载
- 如果 LVGL 启用了主题功能,会自动为屏幕应用默认主题(背景色、默认样式等)。
- 主题可能进一步初始化默认字体、颜色方案等。
- 强制刷新整个屏幕(首次重绘)
- 调用
lv_obj_invalidate(act_scr)标记整个屏幕为“脏”。 - 随后 LVGL 的任务调度器会触发一次全屏重绘:在绘图缓冲区中绘制屏幕背景,并通过
flush_cb发送到物理显示屏。
- 调用
- 使
lv_scr_act()可用lv_scr_act()定义为lv_disp_get_scr_act(lv_disp_get_default()),此时默认显示设备已存在,act_scr已有效,因此可以返回屏幕根控件指针。