事件¶
在 LVGL 中,当某些可能对用户感兴趣的事情发生时会触发事件,例如当一个对象
被点击
被滚动
其值发生变化
被重绘等。
为对象添加事件¶
用户可以为对象分配回调函数以监听其事件。在实践中,它看起来像这样:
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_add_event_cb(btn, my_event_cb, LV_EVENT_CLICKED, NULL); /*分配一个事件回调*/
...
static void my_event_cb(lv_event_t * event)
{
printf("Clicked\n");
}
在这个例子中,LV_EVENT_CLICKED 表示只有点击事件会调用 my_event_cb。查看事件代码列表以了解所有选项。
LV_EVENT_ALL 可用于接收所有事件。
最后一个参数 lv_obj_add_event_cb 是一个指向任何自定义数据的指针,该数据将在事件中可用。稍后将更详细地描述它。
可以向对象添加更多事件,如下所示:
lv_obj_add_event_cb(obj, my_event_cb_1, LV_EVENT_CLICKED, NULL);
lv_obj_add_event_cb(obj, my_event_cb_2, LV_EVENT_PRESSED, NULL);
lv_obj_add_event_cb(obj, my_event_cb_3, LV_EVENT_ALL, NULL); /*无过滤,接收所有事件*/
甚至可以在一个对象上使用相同的事件回调,但具有不同的 user_data。例如:
lv_obj_add_event_cb(obj, increment_on_click, LV_EVENT_CLICKED, &num1);
lv_obj_add_event_cb(obj, increment_on_click, LV_EVENT_CLICKED, &num2);
事件将按照添加的顺序被调用。
其他对象也可以使用相同的事件回调。
从对象中移除事件¶
可以使用 lv_obj_remove_event_cb(obj, event_cb) 函数或 lv_obj_remove_event_dsc(obj, event_dsc) 从对象中移除事件。event_dsc 是 lv_obj_add_event_cb 返回的指针。
事件代码¶
事件代码可以分为以下几类:
输入设备事件
绘图事件
其他事件
特殊事件
自定义事件
所有对象(如按钮/标签/滑块等)无论其类型如何,都会接收输入设备、绘图和其他事件。
然而,特殊事件是特定于某个特定小部件类型的。请参阅小部件文档以了解它们何时被发送。
自定义事件由用户添加,LVGL 永远不会发送这些事件。
以下是现有的事件代码:
输入设备事件¶
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_time之后的每long_press_repeat_time毫秒调用。如果滚动则不会调用。LV_EVENT_CLICKED如果对象没有滚动(无论长按与否),在释放时调用LV_EVENT_RELEASED在任何情况下,当对象被释放时调用LV_EVENT_SCROLL_BEGIN滚动开始。事件参数为NULL或带有滚动动画描述符的lv_anim_t *,如果需要可以修改。LV_EVENT_SCROLL_END滚动结束。LV_EVENT_SCROLL对象被滚动LV_EVENT_GESTURE检测到手势。使用lv_indev_get_gesture_dir(lv_indev_get_act());获取手势LV_EVENT_KEY向对象发送一个键。使用lv_indev_get_key(lv_indev_get_act());获取键LV_EVENT_FOCUSED对象被聚焦LV_EVENT_DEFOCUSED对象失去焦点LV_EVENT_LEAVE对象失去焦点但仍被选中LV_EVENT_HIT_TEST执行高级命中测试。使用lv_hit_test_info_t * a = lv_event_get_hit_test_info(e)并检查a->point是否可以点击对象。如果不能,设置a->res = false
绘图事件¶
LV_EVENT_COVER_CHECK检查对象是否完全覆盖一个区域。事件参数为lv_cover_check_info_t *。LV_EVENT_REFR_EXT_DRAW_SIZE获取对象周围所需的额外绘图区域(例如阴影)。事件参数为lv_coord_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_PART_BEGIN开始绘制一个部分。事件参数为lv_obj_draw_dsc_t *。了解更多这里。LV_EVENT_DRAW_PART_END完成绘制一个部分。事件参数为lv_obj_draw_dsc_t *。了解更多这里。
在 LV_EVENT_DRAW_... 事件中,不允许调整小部件的属性。例如,不能调用 lv_obj_set_width()。
换句话说,只能调用 get 函数。
其他事件¶
LV_EVENT_DELETE对象正在被删除LV_EVENT_CHILD_CHANGED子对象被移除/添加LV_EVENT_CHILD_CREATED子对象被创建,总是冒泡到所有父对象LV_EVENT_CHILD_DELETED子对象被删除,总是冒泡到所有父对象LV_EVENT_SIZE_CHANGED对象坐标/大小已更改LV_EVENT_STYLE_CHANGED对象的样式已更改LV_EVENT_BASE_DIR_CHANGED基本方向已更改LV_EVENT_GET_SELF_SIZE获取小部件的内部大小LV_EVENT_SCREEN_UNLOAD_START屏幕卸载开始,当调用 lv_scr_load/lv_scr_load_anim 时立即触发LV_EVENT_SCREEN_LOAD_START屏幕加载开始,当屏幕更改延迟到期时触发LV_EVENT_SCREEN_LOADED屏幕已加载,当所有动画完成时调用LV_EVENT_SCREEN_UNLOADED屏幕已卸载,当所有动画完成时调用
特殊事件¶
LV_EVENT_VALUE_CHANGED对象的值已更改(即滑块移动)LV_EVENT_INSERT文本正在插入到对象中。事件数据是正在插入的char *。LV_EVENT_REFRESH通知对象刷新其上的某些内容(供用户使用)LV_EVENT_READY进程已完成LV_EVENT_CANCEL进程已取消
自定义事件¶
可以通过 uint32_t MY_EVENT_1 = lv_event_register_id(); 注册任何自定义事件代码。
可以使用 lv_event_send(obj, MY_EVENT_1, &some_data) 将它们发送到任何对象。
发送事件¶
要手动向对象发送事件,请使用 lv_event_send(obj, <EVENT_CODE> &some_data)。
例如,这可以用来通过模拟按钮按下手动关闭消息框(尽管有更简单的方法可以做到这一点):
/*模拟按下第一个按钮(索引从零开始)*/
uint32_t btn_id = 0;
lv_event_send(mbox, LV_EVENT_VALUE_CHANGED, &btn_id);
刷新事件¶
LV_EVENT_REFRESH 是一个特殊事件,因为它旨在让用户通知对象刷新自身。一些示例:
通知标签根据一个或多个变量(例如当前时间)刷新其文本
在语言更改时刷新标签
如果满足某些条件(例如输入正确的 PIN),启用按钮
如果超出限制,向对象添加/移除样式等
lv_event_t 的字段¶
lv_event_t 是传递给事件回调的唯一参数,它包含有关事件的所有数据。可以从中获取以下值:
lv_event_get_code(e)获取事件代码lv_event_get_current_target(e)获取事件发送到的对象。即正在调用其事件处理程序的对象。lv_event_get_target(e)获取最初触发事件的对象(如果启用了事件冒泡,则与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_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE),所有事件也会发送到对象的父对象。如果父对象也启用了 LV_OBJ_FLAG_EVENT_BUBBLE,事件将发送到其父对象,依此类推。
事件的目标参数始终是当前目标对象,而不是原始对象。要在事件处理程序中获取原始目标,请调用 lv_event_get_original_target(e)。
示例¶
按钮点击事件¶
C code
GitHub#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
static void event_cb(lv_event_t * e)
{
LV_LOG_USER("Clicked");
static uint32_t cnt = 1;
lv_obj_t * btn = lv_event_get_target(e);
lv_obj_t * label = lv_obj_get_child(btn, 0);
lv_label_set_text_fmt(label, "%"LV_PRIu32, cnt);
cnt++;
}
/**
* Add click event to a button
*/
void lv_example_event_1(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
lv_obj_center(btn);
lv_obj_add_event_cb(btn, event_cb, LV_EVENT_CLICKED, NULL);
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text(label, "Click me!");
lv_obj_center(label);
}
#endif
class Event_1():
def __init__(self):
self.cnt = 1
#
# Add click event to a button
#
btn = lv.btn(lv.scr_act())
btn.set_size(100, 50)
btn.center()
btn.add_event_cb(self.event_cb, lv.EVENT.CLICKED, None)
label = lv.label(btn)
label.set_text("Click me!")
label.center()
def event_cb(self,e):
print("Clicked")
btn = e.get_target()
label = btn.get_child(0)
label.set_text(str(self.cnt))
self.cnt += 1
evt1 = Event_1()
处理多个事件¶
C code
GitHub#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
static void event_cb(lv_event_t * 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, "The last button event:\nLV_EVENT_PRESSED");
break;
case LV_EVENT_CLICKED:
lv_label_set_text(label, "The last button event:\nLV_EVENT_CLICKED");
break;
case LV_EVENT_LONG_PRESSED:
lv_label_set_text(label, "The last button event:\nLV_EVENT_LONG_PRESSED");
break;
case LV_EVENT_LONG_PRESSED_REPEAT:
lv_label_set_text(label, "The last button event:\nLV_EVENT_LONG_PRESSED_REPEAT");
break;
default:
break;
}
}
/**
* Handle multiple events
*/
void lv_example_event_2(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
lv_obj_center(btn);
lv_obj_t * btn_label = lv_label_create(btn);
lv_label_set_text(btn_label, "Click me!");
lv_obj_center(btn_label);
lv_obj_t * info_label = lv_label_create(lv_scr_act());
lv_label_set_text(info_label, "The last button event:\nNone");
lv_obj_add_event_cb(btn, event_cb, LV_EVENT_ALL, info_label);
}
#endif
def event_cb(e,label):
code = e.get_code()
if code == lv.EVENT.PRESSED:
label.set_text("The last button event:\nLV_EVENT_PRESSED")
elif code == lv.EVENT.CLICKED:
label.set_text("The last button event:\nLV_EVENT_CLICKED")
elif code == lv.EVENT.LONG_PRESSED:
label.set_text("The last button event:\nLV_EVENT_LONG_PRESSED")
elif code == lv.EVENT.LONG_PRESSED_REPEAT:
label.set_text("The last button event:\nLV_EVENT_LONG_PRESSED_REPEAT")
btn = lv.btn(lv.scr_act())
btn.set_size(100, 50)
btn.center()
btn_label = lv.label(btn)
btn_label.set_text("Click me!")
btn_label.center()
info_label = lv.label(lv.scr_act())
info_label.set_text("The last button event:\nNone")
btn.add_event_cb(lambda e: event_cb(e,info_label), lv.EVENT.ALL, None)
事件冒泡¶
C code
GitHub#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_FLEX
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);
}
#endif
def event_cb(e):
# The original target of the event. Can be the buttons or the container
target = e.get_target()
# print(type(target))
# If container was clicked do nothing
if type(target) != type(lv.btn()):
return
# Make the clicked buttons red
target.set_style_bg_color(lv.palette_main(lv.PALETTE.RED), 0)
#
# Demonstrate event bubbling
#
cont = lv.obj(lv.scr_act())
cont.set_size(320, 200)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(30):
btn = lv.btn(cont)
btn.set_size(80, 50)
btn.add_flag(lv.obj.FLAG.EVENT_BUBBLE)
label = lv.label(btn)
label.set_text(str(i))
label.center()
cont.add_event_cb(event_cb, lv.EVENT.CLICKED, None)