【全csdn最前沿LVGL9】事件的高级使用


前言

在现代图形用户界面(GUI)开发中,事件处理是至关重要的一部分。LVGL(LittlevGL)是一个功能强大的开源GUI库,提供了丰富的事件系统,使开发人员能够轻松地实现交互式和响应式的用户界面。本文将探讨LVGL 9中事件处理的高级使用方法,帮助开发人员更好地利用事件系统构建灵活、交互性强的应用程序界面。


一、事件

1.1 从对象删除某个事件

我们可以通过:lv_obj_get_event_count(obj)函数来获取某个obj绑定event的数量
我们可以使用:lv_obj_get_event_dsc(obj, i)这个函数返回对象(obj)的第 i 个事件描述符(lv_event_dsc_t)。事件描述符包含有关特定事件的信息,例如回调函数(callback function)等
lv_event_dsc_get_cb(event_dsc)这个函数用于从事件描述符 (event_dsc) 中获取与之关联的回调函数 (cb,callback function)。回调函数是在事件发生时执行的函数,用于处理该事件。
lv_obj_remove_event(obj, i)这个函数用于从对象 (obj) 的事件列表中移除第 i 个事件。通过这个操作,开发者可以修改对象的事件处理逻辑或者取消特定事件的处理。

示例代码:

uint32_t i;
uint32_t event_cnt = lv_obj_get_event_count(obj);
for(i = 0; i < event_cnt; i++) {
    lv_event_dsc_t * event_dsc = lv_obj_get_event_dsc(obj, i);
    if(lv_event_dsc_get_cb(event_dsc) == some_event_cb) {
        lv_obj_remove_event(obj, i);
        break;
    }
}

我们可以通过遍历整个event数组,通过lv_event_dsc_get_cb找到对应的回调函数,然后进行要删除的回调函数然后去删除

1.2 Event Codes

Input device event

LV_EVENT_PRESSED: 对象已被按下
LV_EVENT_PRESSING: 对象正在被按下(在持续按下时调用)
LV_EVENT_PRESS_LOST: 对象仍然被按下,但光标/手指滑出对象
LV_EVENT_SHORT_CLICKED: 对象被短时间按下,然后释放。如果滚动,则不调用。
LV_EVENT_LONG_PRESSED: 对象已被按下至少 long_press_time。如果滚动,则不调用。
LV_EVENT_LONG_PRESSED_REPEAT: 在每个 long_press_repeat_time 毫秒后调用。如果滚动,则不调用。
LV_EVENT_CLICKED: 在释放时调用,如果没有滚动(与长按无关)
LV_EVENT_RELEASED: 在对象被释放的所有情况下调用
LV_EVENT_SCROLL_BEGIN: 滚动开始。事件参数是指向滚动动画的指针。可以修改。
LV_EVENT_SCROLL_THROW_BEGIN:
LV_EVENT_SCROLL_END: 滚动结束
LV_EVENT_SCROLL: 滚动
LV_EVENT_GESTURE: 检测到手势。使用 lv_indev_get_gesture_dir(lv_indev_active()) 获取手势。
LV_EVENT_KEY: 将键发送到对象。使用 lv_indev_get_key(lv_indev_active()) 获取键。
LV_EVENT_FOCUSED: 对象获得焦点
LV_EVENT_DEFOCUSED: 对象失去焦点
LV_EVENT_LEAVE: 对象失去焦点但仍然被选中
LV_EVENT_HIT_TEST: 执行高级命中测试
LV_EVENT_INDEV_RESET: 输入设备已被重置

Drawing events

LV_EVENT_COVER_CHECK: 检查对象是否完全覆盖一个区域。事件参数是 lv_cover_check_info_t *。
LV_EVENT_REFR_EXT_DRAW_SIZE: 获取对象周围所需的额外绘制区域(例如,用于阴影)。事件参数是 int32_t * 以存储大小。
LV_EVENT_DRAW_MAIN_BEGIN: 开始主绘制阶段
LV_EVENT_DRAW_MAIN: 执行主绘制
LV_EVENT_DRAW_MAIN_END: 完成主绘制阶段
LV_EVENT_DRAW_POST_BEGIN: 开始后绘制阶段(当所有子元素都已绘制时)
LV_EVENT_DRAW_POST: 执行后绘制阶段(当所有子元素都已绘制时)
LV_EVENT_DRAW_POST_END: 完成后绘制阶段(当所有子元素都已绘制时)
LV_EVENT_DRAW_TASK_ADDED: 添加绘制任务

Special events

LV_EVENT_VALUE_CHANGED: 对象的值已更改(例如,滑块移动)
LV_EVENT_INSERT: 文本已插入到对象中。事件数据是被插入的 char *。
LV_EVENT_REFRESH: 通知对象刷新其上的某些内容(供用户使用)
LV_EVENT_READY: 进程已完成
LV_EVENT_CANCEL: 进程已被取消

Other events

LV_EVENT_CREATE: 对象正在被创建
LV_EVENT_DELETE: 对象正在被删除
LV_EVENT_CHILD_CHANGED: 子元素已被移除、添加或其大小、位置已更改
LV_EVENT_CHILD_CREATED: 子元素已被创建,始终冒泡到所有父级
LV_EVENT_CHILD_DELETED: 子元素已被删除,始终冒泡到所有父级
LV_EVENT_SCREEN_UNLOAD_START: 屏幕卸载已开始,立即触发当 scr_load 被调用时
LV_EVENT_SCREEN_LOAD_START: 屏幕加载已开始,触发于屏幕切换延迟过期时
LV_EVENT_SCREEN_LOADED: 屏幕已加载
LV_EVENT_SCREEN_UNLOADED: 屏幕已卸载
LV_EVENT_SIZE_CHANGED: 对象坐标/大小已更改
LV_EVENT_STYLE_CHANGED: 对象的样式已更改
LV_EVENT_LAYOUT_CHANGED: 子元素位置由于布局重新计算而发生变化
LV_EVENT_GET_SELF_SIZE: 获取小部件的内部大小

1.3 发送事件

我们可以使用lv_obj_send_event(obj, <EVENT_CODE>, &some_data)这个函数发送事件
参数1为要发送的对象,参数2为事件code,参数3为附带的data

示例代码:

uint32_t btn_id = 0;
lv_event_send(mbox, LV_EVENT_VALUE_CHANGED, &btn_id);

1.4 刷新事件

LV_EVENT_REFRESH为刷新事件,他是一个特殊的事件
他通常这样使用:
通知标签根据一个或多个变量刷新其文本(例如,当前时间)
在语言更改时刷新标签
如果满足某些条件(例如,输入了正确的 PIN),则启用按钮
如果达到条件,则向对象添加/移除样式,等等。

简而言之就是刷新成最新的,和我们现在网页的刷新一样,更新数据

1.5 关于lv_event_t类型

lv_event_get_code(e): 获取事件的代码。通过这个函数,你可以知道事件的类型或标识。
lv_event_get_current_target(e): 获取事件被发送到的对象。换句话说,就是触发事件处理程序的对象。
lv_event_get_target(e): 获取最初触发事件的对象。如果启用了事件冒泡(bubbling),这可能与 lv_event_get_current_target() 返回的对象不同。
lv_event_get_user_data(e): 获取作为 lv_obj_add_event() 的最后一个参数传递的指针。这是用户在添加事件处理程序时传递的自定义数据。
lv_event_get_param(e): 获取作为 lv_event_send() 的最后一个参数传递的参数。这是在手动发送事件时传递的额外参数。

1.6 事件冒泡

事件冒泡是什么

在LVGL中,Event Bubbling(事件冒泡)是指当一个对象(比如按钮或容器)上发生事件时,这个事件会从该对象一直传递到它的父级或更高层次的对象,直到根对象。就像水泡从底部冒到表面一样,事件也会从内向外逐层传播。

举个例子,假设你点击了一个按钮。在LVGL中,这个点击事件会从按钮开始,然后冒泡到按钮的父容器,再到父容器的父容器,一直传递到根对象。在每一层上,你可以注册相应的事件处理函数,捕捉并响应这个事件。这种事件冒泡的机制使得你可以在整个对象层次结构中更方便地管理和响应事件,而不仅仅局限于事件发生的具体对象。

事件冒泡的使用

如果开启lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE)这个,则这个对象的所有事件都会开启事件冒泡
如果他的父类也开启了事件冒泡,则会冒泡到父类的父类

这句话指的是在LVGL中处理事件时,事件的目标参数(target parameter)始终是当前的目标对象(current target object),而不是最初触发事件的原始对象(original object)。如果你想要获取最初触发事件的原始对象,你需要在事件处理程序中调用 lv_event_get_target_obj(e) 函数。

举个例子,假设你有一个按钮,按钮位于一个容器内。当你点击按钮时,按钮是当前目标对象,但是容器可能也有一个事件处理程序。在容器的事件处理程序中,你可以通过调用 lv_event_get_target(e) 来获取最初触发事件的原始对象,即按钮。

这种区分当前目标对象和原始对象的机制使得在事件处理中能够更准确地了解事件的来源和流向,从而更灵活地处理事件。


总结

通过本文的介绍,我们深入了解了LVGL 9中事件处理的高级使用方法。从事件的基本概念开始,我们探讨了LVGL提供的各种事件类型,以及如何利用事件回调函数来响应用户输入和系统事件。我们还学习了如何使用事件参数来获取事件相关的信息,以及如何结合LVGL的其他功能来实现更复杂的交互逻辑。通过合理地利用事件系统,开发人员可以为他们的应用程序创建出更加灵活、响应式的用户界面,提升用户体验并增强应用程序的交互性。