LVGL第一阶段

目录

什么是LVGL?

为什么选择LVGL?

LVGL开发参考手册

下载并安装git

Git工作原理简明介绍

安装Code::Block

 Code::Block运行LVGL

2-1-1_对象(lv_obj_t)

 屏幕对象的创建过程

LVGL的三层屏幕

主函数代码:

 2-2-2_基础对象的大小(size)

代码:

2-2-3_基础对象的位置(Position)

 位置(Position)

对齐(Alignment)

对齐类型(LV_ALIGN_...)

代码:

 2-2-4_基础对象的盒子模型(border-box)

代码:

2-2-5_基础对象的样式(styles)

初始化样式

设置样式属性

添加(应用)样式到对象

获取样式属性

删除样式

查看样式属性

背景部分的属性

样式的状态和部分

状态(States)

部分(Part)

本地样式

样式继承

代码:

2-2-6_基础对象的事件(events)

什么是事件?

添加事件

发送事件

删除事件

事件类型(event_code)

事件回调函数的 lv_event_t 参数

其他 

事件冒泡 

代码:


什么是LVGL?

LVGL是一个轻量级的嵌入式图形库。LVGL的项目作者是来自匈牙利首都布达佩斯的 Gábor Kiss-Vámosi 。Kiss 在2016年将其发布在 GitHub上。 当时叫 LittlevGL而不是LVGL,后来作者重新命名为 LVGL,甚至连仓库地址都改了。 像一般的开源项目的那样,它是作为一个人的项目开始的。 从那时起,陆续有近 100 名贡献者参与了项目开发,使得 LVGL 逐渐成为最受欢迎的嵌入式图形库之一。

为什么选择LVGL?

LVGL是一个轻便且多功能的图形库,我们可以在官网查看她的所有特性。

LVGL开发参考手册

  • LVGL为我们提供一个详细的文档手册,
  • 这个文档的在线阅读站点是:https://docs.lvgl.io
  • 百问网LVGL中文站点:http://lvgl.100ask.net

下载并安装git

  • Git 是一个免费开源的分布式版本控制系统,用于快速高效地处理从小到大的所有项目
  • 现在的实际项目开发或者工作中一般都会使用git来管理项目代码。
  • 尽早学会使用 git 对我们的学习和未来参加工作是有益而无害的!
  • Windows Git下载地址: https://git-scm.com/download/win
  • 下载完成之后双击直接打开,按照默认的配置点击下一步安装即可。

Git工作原理简明介绍

  • 安装完成之后,打开 git bash 配置用户名和邮箱,如果没有git账户,可以这样设置:   
  •  git config --global user.name "100ask"     
  • git config --global user.email "100ask@100ask.com"
  • 打开git bash,执行下面的命令克隆仓库:   
  •  git clone https://gitee.com/weidongshan/lvgl_100ask_course_materials.git
  • 拉取仓库资料更新,进入到 lvgl_100ask_course_materials 目录,打开 git bash 执行:   
  •  git pull origin master
  • 课程资料会随着课程发布进度更新,所以在学习的时候,不要动克隆下来的仓库,可以自己复制一份副本自用,我们需要克隆的那份仓库用来拉取同步更新

安装Code::Block

Code::Block在资料中 “03_开发软件/codeblocks-20.03mingw-setup”,选中“codeblocks-20.03mingw-setup.zip”右键进行解压分卷包:

解压后,双击“codeblocks-20.03mingw-setup.exe”安装Code::Block:

 

 Code::Block运行LVGL

成功安装了 Code::Block 之后,进入下面这个目录双击 “lvgl.cbp” 打开项目:

2-1-1_对象(lv_obj_t)

LVGL采用面向对象的编程思想(OOP),她的基本构造块(类)是对象(实例),也就是我们所说的部件(Widgets)就是一个个部件,比如button、label、image等等。

  • 在LVGL中,所有的对象都在 lv_obj_t 这个结构体的基础上进行演变,所以我们就看到了各种不一样的部件,就算是一样的部件,继承基础父类(基类)之后演变出来对象(实例)的形态或风格样式都不一样 (就像狗有不一样的品种,不一样的品种就有不一样的体型、外观;就算是同一品种的狗它的毛色、性格都会不一样等等)。
  • 比如不同的部件就有不一样的效果,按钮和下拉列表。
  • 比如同样创建出来的按钮部件,你可以是红色的,我的是蓝色的,他的是有阴影效果并且有被按下时不同的互动效果等等。这样我们看到就是多姿多彩的用户界面了,每个人写出来的界面可能都不一样!
  • 由于lvgl使用c语言编写,因此 lv_obj_t 只能通过结构体来表示,它并不是一个实例化后的类,因此我们需要先实例化出一个父类(基类),其他所有的部件(对象)都继承自这个父类(基类),也就是我们下节课说到的基础对象(lv_obj)。

 

 屏幕对象的创建过程

lv_init
    _lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t)); // 初始化显示器链表
lv_disp_drv_register
     _lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll)); 	// 注册显示器到链表
    disp->act_scr   = lv_obj_create(NULL);  	// 在显示器上创建一个默认屏幕
        lv_obj_class_create_obj
            obj->coords.x1 = 0;
            obj->coords.y1 = 0;
            obj->coords.x2 = lv_disp_get_hor_res(NULL) - 1; // 设置屏幕的水平宽度
            obj->coords.y2 = lv_disp_get_ver_res(NULL) - 1; // 设置屏幕的垂直高度


    

LVGL的三层屏幕

lv_scr_act(void);     // 活动屏幕      disp->act_scr

lv_layer_top (void);     // 顶层     disp->top_layer

lv_layer_sys (void);    // 系统层     disp->sys_layer

主函数代码:


/**
 * @file main
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include <stdlib.h>
#include <unistd.h>

#include "lvgl/lvgl.h"
#include "lv_100ask_teach_demos/lv_100ask_teach_demos.h"
#include "lv_demos/src/lv_demo_widgets/lv_demo_widgets.h"
#include "lv_drivers/win32drv/win32drv.h"

#include <windows.h>


/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void hal_init(void);
static int tick_thread(void *data);

/**********************
 *  STATIC VARIABLES
 **********************/

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nCmdShow)
{
    /*Initialize LittlevGL*/
    lv_init();

    /*Initialize the HAL for LittlevGL*/
    lv_win32_init(hInstance, SW_SHOWNORMAL, 1024, 600, NULL);

    /*Output prompt information to the console, you can also use printf() to print directly*/
    LV_LOG_USER("LVGL initialization completed!");
    //printf("www.100ask.net: Lvgl initialization complete!\n");


    /*Run the demo*/
    //lv_100ask_demo_course_2_1_1();      // 基础对象(lv_obj),"Hello, LVGL!"
    //lv_100ask_demo_course_2_2_2();    // 基础对象的大小(size)
    //lv_100ask_demo_course_2_2_3();    // 基础对象的位置(position)
    //lv_100ask_demo_course_2_2_4();    // 基础对象的盒子模型(border-box)
	//lv_100ask_demo_course_2_2_5();    // 基础对象的样式(styles)
	  lv_100ask_demo_course_2_2_6();    // 基础对象的事件(events)、事件冒泡

	//lv_100ask_demo_course_3_1_1();    // 组件(widgets): 标签(label)的用法
	//lv_100ask_demo_course_3_1_2();    // 组件(widgets): 标签(label),显示中文
	//lv_100ask_demo_course_3_2_1();    // 组件(widgets): 按钮(lv_btn)的用法
	//lv_100ask_demo_course_3_3_1();    // 组件(widgets): 使用物理按键代替触摸(groups)
	//lv_100ask_demo_course_3_4_1();    // 组件(widgets): 开关(lv_switch)的用法
	//lv_100ask_demo_course_3_5_1();    // 组件(widgets): 复选框(lv_checkbox)的用法
	//lv_100ask_demo_course_3_6_1();    // 组件(widgets): 下拉列表(lv_dropdown))的用法
	//lv_100ask_demo_course_3_7_1();    // 组件(widgets): 滚轮(lv_roller)的用法
	//lv_100ask_demo_course_3_8_1();    // 组件(widgets): 进度条(lv_bar)的用法
	//lv_100ask_demo_course_3_9_1();    // 组件(widgets): 进度条(lv_slider)的用法
	//lv_100ask_demo_course_3_10_1();   // 组件(widgets): 圆弧(lv_arc)的用法
	//lv_100ask_demo_course_3_10_3();   // 组件(widgets): 圆弧(lv_arc)-综合实战
    //lv_100ask_demo_course_3_11_1();   // 定时器: 定时器(lv_timer)的用法
    //lv_100ask_demo_course_3_11_2();   // 为什么创建出来的组件获取到的宽高是0?(在学习2_2_2时遇到的问题)
    //lv_100ask_demo_course_3_11_3();   // 为什么创建出来的组件获取到的坐标不正确?(在学习2_2_3时遇到的问题)
    //lv_100ask_demo_course_3_12_1();   // 组件(widgets): 线条(lv_line)的用法
    //lv_100ask_demo_course_3_12_2();   // 组件(widgets): 线条(lv_line)实战
    //lv_100ask_demo_course_3_13_1();   // 组件(widgets): 文本框(lv_textarea)的用法
    //lv_100ask_demo_course_3_14_1();   // 组件(widgets): 按钮矩阵(lv_btnmatrix)的用法
    //lv_100ask_demo_course_3_14_2();   // 组件(widgets): 按钮矩阵(lv_btnmatrix)和按钮(lv_btn)的对比(显示多个按钮谁更轻量级?)

    //lv_100ask_demo_course_6_1_1();    // 第三方库(lv_fs):通过LVGL文件系统接口统一不同的文件系统并读取文件、读取目录内容


    while(!lv_win32_quit_signal) {
        /* Periodically call the lv_task handler.
         * It could be done in a timer interrupt or an OS task too.*/
        lv_task_handler();
        usleep(10000);       /*Just to let the system breath*/
    }
    return 0;
}

 2-2-2_基础对象的大小(size)

大小(Size)

//设置宽度
lv_obj_set_width(obj, new_width);
//设置高度:
lv_obj_set_height(obj, new_height);
//同时设置宽度、高度:
lv_obj_set_size(obj, new_ width, new_ height);

获取大小(Get size)

//获取宽度:
lv_obj_get_width(obj);
//获取高度:
lv_obj_get_height(obj);

代码:


void lv_100ask_demo_course_2_2_2(void)
{
    lv_obj_t * obj = lv_obj_create(lv_scr_act());
    //lv_obj_set_width(obj, 300);
    //lv_obj_set_height(obj, 500);
    lv_obj_set_size(obj,600, 300);

    //printf("w:%d\n", lv_obj_get_width(obj));
    //printf("h:%d\n", lv_obj_get_height(obj));
}

2-2-3_基础对象的位置(Position)

 位置(Position)

设置x轴方向的坐标位置:

lv_obj_set_x(obj, new_x);

设置y轴方向的坐标位置:

lv_obj_set_y(obj, new_y);

同时设置x、y坐标位置:

lv_obj_set_pos(obj, new_x, new_y);  // position

对齐(Alignment)

参照父对象对齐:

lv_obj_set_align(obj, LV_ALIGN_...);

参照父对象对齐后再设置坐标位置:

lv_obj_align(obj, LV_ALIGN_..., x, y);

参照另一个对象(无父子关系)对齐后设置坐标位置:

lv_obj_align_to(obj_to_align, obj_referece, LV_ALIGN_..., x, y)

对齐类型(LV_ALIGN_...)

代码:

void lv_100ask_demo_course_2_2_3(void)
{
    lv_obj_t * obj = lv_obj_create(lv_scr_act());
    //lv_obj_set_x(obj, 200);
    //lv_obj_set_y(obj, -50);
    //lv_obj_set_pos(obj, 100, 100);
     lv_obj_set_align(obj, LV_ALIGN_CENTER);
    //lv_obj_align(obj, LV_ALIGN_CENTER, 100, 100);

    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "H!");
    lv_obj_align_to(label, obj, LV_ALIGN_OUT_LEFT_MID, 0, 0);

    //printf("w:%d\n", lv_obj_get_x(obj));
    //printf("h:%d\n", lv_obj_get_y(obj));
}

 2-2-4_基础对象的盒子模型(border-box)

代码:

void lv_100ask_demo_course_2_2_4(void)
{
    lv_obj_t * obj1 = lv_obj_create(lv_scr_act());
    lv_obj_align(obj1, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_style_border_width(obj1, 10, 0);
    lv_obj_set_style_outline_width(obj1, 10, 0);

#if 0
    lv_obj_t * obj2 = lv_obj_create(lv_scr_act());
    lv_obj_t * obj_out_top = lv_obj_create(lv_scr_act());
    lv_obj_t * obj_out_bottom = lv_obj_create(lv_scr_act());
    lv_obj_t * obj_out_left = lv_obj_create(lv_scr_act());
    lv_obj_t * obj_out_right = lv_obj_create(lv_scr_act());
    //lv_obj_set_style_outline_width(obj_out_left, 10, 0);

    lv_obj_align(obj1, LV_ALIGN_CENTER, 0, 0);
    lv_obj_align_to(obj_out_top, obj1, LV_ALIGN_OUT_TOP_MID, 0, 0);
    lv_obj_align_to(obj_out_bottom, obj1, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
    lv_obj_align_to(obj_out_left, obj1, LV_ALIGN_OUT_LEFT_MID, 0, 0);
    lv_obj_align_to(obj_out_right, obj1, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
    lv_obj_align_to(obj2, obj_out_right, LV_ALIGN_OUT_TOP_MID, 0, 0);
#endif
}


#endif /* LV_USE_100ASK_DEMO_COURSE_2_2_4 */

2-2-5_基础对象的样式(styles)

初始化样式

样式存储在 lv_style_t 变量中。样式变量应该是 静态 、全局或动态分配 的。 也就是它们不能是函数中的局部变量,因为当函数结束时它们会被销毁。样式初始化示例:   

static lv_style_t style_obj;     

lv_style_init(&style_obj);

设置样式属性

当我们初始化好一个样式之后就可以设置它的样式属性了,接口函数是这样的格式:     lv_style_set_<property_name>(&style, <value>);

示例:   

 lv_style_set_bg_color(&style_obj, lv_color_hex(0x000000));   // 设置背景色     lv_style_set_bg_opa(&style_obj, LV_OPA_50);                        // 设置背景透明度     lv_style_set_....

添加(应用)样式到对象

当我们初始化并且设置好一个样式之后就可以将它添加到对象上面了,接口函数只有一个:     lv_obj_add_style(obj, &style, <selector>)

参数 “obj” 就是要添加到的对象,“style” 是指向样式变量的指针,<selector> 是应添加样式的部分和状态的 OR-ed 值 (不能是互斥,否则就是清除标志,没法合并)。示例:     lv_obj_add_style(obj, &style_obj, 0);                       // 默认(常用)   

 lv_obj_add_style(obj, &style_obj, LV_STATE_PRESSED);  // 在对象被按下时应用样式

获取样式属性

我们可以获取属性的最终值(考虑级联、继承、本地样式和转换),接口函数是这样的格式:     

lv_obj_get_style_<property_name>(obj, <part>);

函数使用对象的当前状态,如果没有更好的候选对象,则返回默认值。 例如:   

 lv_color_t color = lv_obj_get_style_bg_color(obj, LV_PART_MAIN);

删除样式

删除对象的所有样式:     

lv_obj_remove_style_all(obj);

删除对象的特定样式:     

lv_obj_remove_style(obj, &style_obj, selector);

只有当 selector 与 lv_obj_add_style 中使用的 selector 匹配时,此函数才会删除 style 如果 style 是空,那么会根据给出的 selector 检查并删除所有匹配的样式 如果 selector 是 LV_STATE_ANY 或 LV_PART_ANY 就会删除具有任何状态或部分的样式。下面这个效果和lv_obj_remove_style_all 的效果是一样的:     

lv_obj_remove_style(obj, NULL, LV_STATE_ANY | LV_PART_ANY );

查看样式属性

所有的可用的样式属性我们可以在文档或者代码中获取得到。

文档位置:     

英文原版:https://docs.lvgl.io/8.1/overview/style-props.html     

中文翻译:http://lvgl.100ask.net/8.1/overview/style-props.html

代码位置:     

普通样式:lvgl/src/misc/lv_style_gen.h     

本地样式:lvgl/src/core/lv_obj_style_gen.h

文档位置和代码位置可能在后续的版本更新中会发生变化,这里的方法只是提供参考,不需要死记硬背函数接口名。

背景部分的属性

背景属性和我们前面学习的盒子模型关系很大,背景属性主要有一下这些:

  • 背景(Background)
  • 边界(Border)
  • 轮廓(Outline)
  • 阴影(Shadow)
  • 填充(Padding)
  • 宽度和高度变换
  • X和Y变换

样式的状态和部分

状态(States)

对象可以处于以下状态的组合:

LV_STATE_DEFAULT (0x0000) 正常,释放状态

LV_STATE_CHECKED (0x0001) 切换或检查状态

LV_STATE_FOCUSED (0x0002) 通过键盘或编码器聚焦或通过触摸板/鼠标点击 LV_STATE_FOCUS_KEY (0x0004) 通过键盘或编码器聚焦,但不通过触摸板/鼠标聚焦 LV_STATE_EDITED (0x0008) 由编码器编辑

LV_STATE_HOVERED (0x0010) 鼠标悬停(现在不支持)

LV_STATE_PRESSED (0x0020) 被按下

LV_STATE_SCROLLED (0x0040) 正在滚动

LV_STATE_DISABLED (0x0080) 禁用状态

LV_STATE_USER_1 (0x1000) 自定义状态

LV_STATE_USER_2 (0x2000) 自定义状态

LV_STATE_USER_3 (0x4000) 自定义状态

LV_STATE_USER_4 (0x8000) 自定义状态

这些可能会随着lvgl的更新而不断增加,同学们可以阅读最新版本的文档获取最新资料。

部分(Part)

对象可以有 部分(parts) ,它们也可以有自己的样式。LVGL 中存在以下预定义部分:

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 可以从这里添加自定义部件。

这些可能会随着lvgl的更新而不断增加,同学们可以阅读最新版本的文档获取最新资料。

本地样式

除了“普通” 样式外,对象还可以存储 本地样式(私有样式) 。

本地样式与普通样式类似,但是它不能在其他对象之间共享。如果使用本地样式,将自动分配局部样式,并在删除对象时释放。本地样式对于向对象添加本地自定义很有用。

本地样式的接口函数是这样的格式:     

lv_obj_set_style_<property_name>(obj, <value>, <selector>);

示例:   

 lv_obj_set_style_bg_color(obj,  lv_color_hex(0xffffff), 0);   // 设置背景色     lv_obj_set_style_bg_opa(obj, LV_OPA_50, 0);                  // 设置背景透明度     lv_style_set_style_....

删除本地样式的时候我们删除某一个样式:     

lv_obj_remove_local_style_prop(obj, LV_STYLE_..., selector);

LV_STYLE_...的取值请看: lvgl/src/misc/lv_style.h 中的 lv_style_prop_t

样式继承

某些属性(通常与文本相关)可以从父对象的样式继承。 只有没有在为对象设置样式属性的时候,才应用继承。 在这种情况下,如果这个属性是可继承的,那这个属性的值会在父类中检索,直到一个对象为该属性指定了一个值。父类将使用自己的状态来确定该值。 因此,如果按下按钮,并且文本颜色来自此处,则将使用按下的文本颜色。

代码:

static void lv_example_slider_2(void)
{
    /*Create a transition*/
    static const lv_style_prop_t props[] = {LV_STYLE_BG_COLOR, 0};
    static lv_style_transition_dsc_t transition_dsc;
    lv_style_transition_dsc_init(&transition_dsc, props, lv_anim_path_linear, 300, 0, NULL);

    static lv_style_t style_main;           // 矩形背景部分
    static lv_style_t style_indicator;      // 指针部分
    static lv_style_t style_knob;           // 旋钮部分
    static lv_style_t style_pressed_color;  // 对象某部分被按下时,该部分样式应用的颜色

    // 矩形背景部分
    lv_style_init(&style_main);
    lv_style_set_bg_opa(&style_main, LV_OPA_COVER);
    lv_style_set_bg_color(&style_main, lv_color_hex3(0xbbb));
    //lv_style_set_outline_width(&style_main, 5);
    //lv_style_set_border_width(&style_main, 2);
    lv_style_set_radius(&style_main, LV_RADIUS_CIRCLE);
    lv_style_set_pad_ver(&style_main, -2); /*Makes the indicator larger*/

    // 指针部分
    lv_style_init(&style_indicator);
    lv_style_set_bg_opa(&style_indicator, LV_OPA_COVER);
    lv_style_set_bg_color(&style_indicator, lv_palette_main(LV_PALETTE_CYAN));
    lv_style_set_radius(&style_indicator, LV_RADIUS_CIRCLE);
    lv_style_set_transition(&style_indicator, &transition_dsc);

    // 旋钮部分
    lv_style_init(&style_knob);
    lv_style_set_bg_opa(&style_knob, LV_OPA_COVER);
    lv_style_set_bg_color(&style_knob, lv_palette_main(LV_PALETTE_CYAN));
    lv_style_set_border_color(&style_knob, lv_palette_darken(LV_PALETTE_CYAN, 3));
    lv_style_set_border_width(&style_knob, 2);
    lv_style_set_radius(&style_knob, LV_RADIUS_CIRCLE);
    lv_style_set_pad_all(&style_knob, 6); /*Makes the knob larger*/
    lv_style_set_transition(&style_knob, &transition_dsc);

    // 对象某部分被按下时,该部分样式应用的颜色
    lv_style_init(&style_pressed_color);
    lv_style_set_bg_color(&style_pressed_color, lv_palette_darken(LV_PALETTE_CYAN, 2));

    /*Create a slider and add the style*/
    lv_obj_t * slider = lv_slider_create(lv_scr_act());

    // 体验流程:先体验 lv_obj_add_style 都被注释时的效果;然后一个个去掉注释
    lv_obj_remove_style_all(slider);                                                        // 删除对象的所有样式,然后下面再添加我们自定义的样式
    lv_obj_add_style(slider, &style_main, LV_PART_MAIN);                                    // 矩形背景部分
    lv_obj_add_style(slider, &style_indicator, LV_PART_INDICATOR);                          // 指针部分
    lv_obj_add_style(slider, &style_pressed_color, LV_PART_INDICATOR | LV_STATE_PRESSED);   // 当指针部分被按下的时候,指针部分应用该样式
    lv_obj_add_style(slider, &style_knob, LV_PART_KNOB);                                    // 旋钮部分,像按钮一样可以抓取调整值
    lv_obj_add_style(slider, &style_pressed_color, LV_PART_KNOB | LV_STATE_PRESSED);        // 当旋钮部分被按下的时候,旋钮部分应用该样式

    lv_obj_center(slider);
}

void lv_100ask_demo_course_2_2_5(void)
{

    // 正常样式
    static lv_style_t style_obj;

	lv_style_init(&style_obj);
    lv_style_set_bg_color(&style_obj, lv_color_hex(0x000000));      // 设置背景色
    lv_style_set_text_color(&style_obj, lv_color_hex(0xc43e1c));    // 设置文字颜色
    //lv_style_set_bg_color(&style_obj, lv_color_hex(0xc43e1c));    // 设置背景色
    //lv_style_set_bg_opa(&style_obj, 30);                          // 设置透明度

    // 创建对象
    lv_obj_t * obj = lv_obj_create(lv_scr_act());

     lv_obj_t * obj2 = lv_obj_create(lv_scr_act());
    //lv_obj_align(obj2, LV_ALIGN_CENTER, 0 ,0);

    // 本地样式
    //lv_obj_set_style_bg_color(obj,  lv_color_hex(0xc43e1c), LV_STATE_PRESSED);    // 设置背景色
    //lv_obj_set_style_bg_color(obj2,  lv_color_hex(0xc43e1c), LV_STATE_PRESSED);   // 设置背景色
    //lv_obj_set_style_bg_opa(obj, LV_OPA_50, 0);	                                // 设置背景透明度

    // 添加样式到对象
    lv_obj_add_style(obj, &style_obj, 0);                   // 默认状态: LV_STATE_DEFAULT
    lv_obj_add_style(obj2, &style_obj, 0);                  // 默认状态: LV_STATE_DEFAULT
    lv_obj_add_style(obj, &style_obj, LV_STATE_PRESSED);  // 按下状态,当对象被按下的时候应用该样式
    lv_obj_add_style(obj2, &style_obj, LV_STATE_PRESSED); // 按下状态,当对象被按下的时候应用该样式



    // 滑杆示例(不需要深入研究,体会部件样式的部分和状态即可),看里面的注释:体验流程
    //lv_example_slider_2();
}


#endif /* LV_USE_100ASK_DEMO_COURSE_2_2_5 */

2-2-6_基础对象的事件(events)

什么是事件?

当发生用户可能感兴趣的事情时,LVGL 中会触发事件,例如当一个对象:

  • 被点击
  • 滚动
  • 数值改变
  • 重绘
  • 等等。。。

添加事件

lv_obj_add_event_cb(obj, event_cb, event_code, user_data);

发送事件

lv_event_send(obj, event_cb, event_code, user_data);

删除事件

lv_obj_remove_event_cb(obj, event_cb); lv_obj_remove_event_dsc(obj, event_dsc);    //event_dsc 是 lv_obj_add_event_cb 返回的指针

事件类型(event_code)

  • 输入设备事件(Input device events)
  • 绘图事件(Drawing events)
  • 其他事件(Special events)
  • 特殊事件(Other events)
  • 自定义事件(Custom events)

更全面的信息请查阅:   

 源码:lvgl/src/core/lv_event.h    (lv_event_code_t)

开发文档:     

英文:https://docs.lvgl.io/8.1/overview/event.html#event-codes     

中文:http://lvgl.100ask.net/8.1/overview/event.html#event-codes

事件回调函数的 lv_event_t 参数

事件回调函数只有一个参数,这个参数对我们的作为非常大,现在的版本提供这些功能:

static void my_event_cb(lv_event_t * event);

获取触发的事件代码:     

lv_event_code_t code = lv_event_get_code(e);

获取触发事件的对象:     

lv_obj_t * target = lv_event_get_target(e);

获取最初触发事件的对象(事件冒泡):     

lv_obj_t * target = lv_event_get_current_target(e);

获取事件传递的用户数据:     

lv_event_get_user_data(e); 获取使用 lv_obj_add_event_cb 传递的用户数据    lv_event_get_param(e); 获取使用 lv_event_send 传递的用户数据 

一个事件回调函数可给多个对象使用

我们创建了一个事件处理函数之后是可以给不同的对象使用的。

一个对象可以使用多个事件回调函数

我们创建的对象可以绑定多个事件,比如一个事件是处理点击类型的事件,一个事件处理按下类型的事件等等。

其他 

如果传入的用户数据不一样,一个对象可以绑定同一个事件回调函数多次,事件将按照添加的顺序调用。例如:

lv_obj_add_event_cb(obj, my_clicked_event_cb, LV_EVENT_CLICKED, &num1); lv_obj_add_event_cb(obj, my_clicked_event_cb, LV_EVENT_CLICKED, &num2);

事件冒泡 

如果对象启用了 lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE),该对象的所有事件将会发送到该对象的父级。如果父级也启用了 LV_OBJ_FLAG_EVENT_BUBBLE,那么事件继续发送到他的父级,依此类推。

lv_event_get_target(e); 获取触发事件的当前对象。

lv_event_get_current_target(e); 获取事件冒泡的父对象。

代码:

#if 0
static void my_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);        // 获取触发事件的部件(对象)
    lv_event_code_t code = lv_event_get_code(e);    // 获取当前部件(对象)触发的事件代码
    lv_obj_t * label = lv_event_get_user_data(e);   // 获取添加事件时传递的用户数据

    switch(code){
        case LV_EVENT_PRESSED:
            lv_label_set_text(label, "LV_EVENT_PRESSED");
            lv_obj_set_style_bg_color(obj, lv_color_hex(0xc43e1c), 0);  // 通过本地样式(私有样式)设置背景色
            printf("LV_EVENT_PRESSED\n");
            break;
        case LV_EVENT_LONG_PRESSED:
            lv_label_set_text(label, "LV_EVENT_LONG_PRESSED");
            lv_obj_set_style_bg_color(obj, lv_color_hex(0x4cbe37), 0);  // 通过本地样式(私有样式)设置背景色
            printf("LV_EVENT_LONG_PRESSED\n");
            break;
        default:
            //printf("NONE\n");
            break;
    }
}

void lv_100ask_demo_course_2_2_6(void)
{
    /* 创建基础部件(对象) */
    lv_obj_t * obj = lv_obj_create(lv_scr_act());

    /* 创建label部件(对象) */
    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "test");   // 设置label展示的文字
    lv_obj_center(label);               // 将对象与其父对象的中心对齐,这里的父对象是屏幕:lv_scr_act()

    // 为obj1添加事件回调函数,所有的事件类型都能触发该回调函数
    lv_obj_add_event_cb(obj, my_event_cb, LV_EVENT_ALL, label);
}
#endif // 0



/* 事件冒泡 */
#if 1
static void my_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);            // 获取触发事件的对象
    lv_obj_t * parent = lv_event_get_current_target(e); // 获取触发事件对象的父对象(事件冒泡才有)
    lv_event_code_t code = lv_event_get_code(e);        // 获取当前部件触发的事件代码
    lv_obj_t * label = lv_event_get_user_data(e);       // 获取添加事件时传递的用户数据

    switch(code){
        case LV_EVENT_PRESSED:
            lv_label_set_text(label, "LV_EVENT_PRESSED");
            lv_obj_set_style_bg_color(parent, lv_color_hex(0xc43e1c), 0);   // 通过本地样式(私有样式)设置背景色
            lv_obj_set_style_bg_color(obj, lv_color_hex(0xc43e1c), 0);      // 通过本地样式(私有样式)设置背景色
            printf("LV_EVENT_PRESSED\n");
            break;
        case LV_EVENT_CLICKED:
            lv_label_set_text(label, "LV_EVENT_CLICKED");
            lv_obj_remove_local_style_prop(parent, LV_STYLE_BG_COLOR, 0);   // 删除通过本地样式(私有样式)设置的背景色
            lv_obj_remove_local_style_prop(obj, LV_STYLE_BG_COLOR, 0);      // 删除通过本地样式(私有样式)设置的背景色
            printf("LV_EVENT_CLICKED\n");
            break;
        default:
            //printf("NONE\n");
            break;
    }
}

void lv_100ask_demo_course_2_2_6(void)
{
    /* 创建一个基础对象 obj1 */
    lv_obj_t * obj1 = lv_obj_create(lv_scr_act());
    lv_obj_set_size(obj1, 450, 250);
    lv_obj_center(obj1);                                // 将对象与其父对象的中心对齐,这里的父对象是屏幕:lv_scr_act()

    /* 以 obj1 创建一个基础对象 obj2 */
    lv_obj_t * obj2 = lv_obj_create(obj1);
    lv_obj_set_size(obj2, 400, 200);
    lv_obj_center(obj2);                                // 将对象与其父对象的中心对齐,这里的父对象是屏幕:obj1
    lv_obj_add_flag(obj2, LV_OBJ_FLAG_EVENT_BUBBLE);    // 启用事件冒泡,将接收到的所有事件传播给父级

    /* 以 obj2 创建一个基础对象 obj3 */
    lv_obj_t * obj3 = lv_obj_create(obj2);
    lv_obj_set_size(obj3, 350, 150);
    lv_obj_center(obj3);                                // 将对象与其父对象的中心对齐,这里的父对象是屏幕:obj2
    lv_obj_add_flag(obj3, LV_OBJ_FLAG_EVENT_BUBBLE);    // 启用事件冒泡,将接收到的所有事件传播给父级

    /* 以 obj3 创建一个基础对象 obj4 */
    lv_obj_t * obj4 = lv_obj_create(obj3);
    lv_obj_set_size(obj4, 300, 100);
    lv_obj_center(obj4);                                // 将对象与其父对象的中心对齐,这里的父对象是屏幕:obj3
    lv_obj_add_flag(obj4, LV_OBJ_FLAG_EVENT_BUBBLE);    // 启用事件冒泡,将接收到的所有事件传播给父级

    /* 以屏幕为父类,创建一个label部件(对象) */
    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "test");                               // 设置label展示的文字
    lv_obj_align_to(label, obj1, LV_ALIGN_OUT_TOP_MID, 0, 0);       // 将label相对于obj1对齐

    // 将给obj1添加事件回调函数,所有的事件类型都能触发该回调函数
    lv_obj_add_event_cb(obj2, my_event_cb, LV_EVENT_ALL, label);
}
#endif // 1

#endif /* LV_USE_100ASK_DEMO_COURSE_2_2_6 */

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈学弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值