LVGL多个对象公用一个回调函数的算法
如果我们使用传统的LVGL对象公用一个回调函数,可能使用以下源码操作,为了俭省代码的篇幅如以下源码所示,所以利用链表的形式查找那个对象按下。
void event_cb(lv_event_t *event)
{
lv_event_code_t code = lv_event_get_code(event);
lv_obj_t * obj = lv_event_get_target(event);
if (code == LV_EVENT_CLICKED)
{
if (obj == obj1)
{
/* 进行对象1的代码 */
}
else if (obj == obj2)
{
/* 执行对象2的代码 */
}
else if ()
{
/* 多个对象 */
}
........
}
}
如果按照上述的写法,造成获取对象是否按下的代码篇幅很大等问题,我们怎么样去简化这个代码呢。
既然我们把多个对象公共一个回调函数,那么我们可以先把共用的lvgl对象控制块放到一个数组里面,如以下源码所示:
lv_obj_t *lv_obj_app[20];/* 这里可以设置多个对象 */
然后呢?小编主要参考FreeRTOS的内核寻找最高优先级的算法,首先先定义一个32位的变量,如以下源码所示:
/* obj就绪表-->32位的 */
unsigned int obj_readly_list;
注意:这里就是一个无符号的整形,所以一开始就是32bit(000000.....00)
然后我们在回调函数中遍历按下的对象
void event_cb(lv_event_t *event)
{
lv_event_code_t code = lv_event_get_code(event);
lv_obj_t * obj = lv_event_get_target(event);
if (code == LV_EVENT_CLICKED)
{
for (int i = 0;i < app_mun;i ++)
{
if (obj == lv_obj_app[i])
{
/* obj就绪表位置1 */
obj_readly_list |= 1 << i;
}
}
/* 计算前导指令 */
lv_trigger_bit = (31UL - ( unsigned char )
__clz( ( obj_readly_list ) ) );
/* 该位清零就绪表 */
obj_readly_list &= ~(1 << lv_trigger_bit);
/* 根据该位做相应的函数 */
switch(lv_trigger_bit)
{
case 0:
/* 对象0处理的任务 */
break;
case 1:
/* 对象1处理的任务 */
break;
case 2:
/* 对象2处理的任务 */
break;
case 3:
/* 对象3处理的任务 */
break;
case 4:
/* 对象4处理的任务 */
break;
default:
break;
}
}
}
代码分析
上述源码可知:for语句主要就是或者按下的对象,例如我们有5个LVGL对象,保存在一个数组lv_obj_app里面
所以lv_obj_app[0]等于obj0、
lv_obj_app [1]等于obj1、
lv_obj_app [2]等于obj2、
lv_obj_app [3]等于obj3、
lv_obj_app [4]等于obj4。
当按下obj0时,然后调用以下函数对象就绪表obj_readly_list相应位置1,如以下源码所示:
obj_readly_list |= 1 << i; /* 也就是说:obj_readly_list = (0...001); */
然后调用以下函数获取就绪链表的就绪位那个为1,如以下源码所示:
/* 计算前导指令 */
lv_trigger_bit = (31UL - ( unsigned char )
__clz( ( obj_readly_list ) ) );
__clz这个函数就是计算前导0的个数,什么意思呢,例如__clz(00001)= 4,因为前面是4个0,所以等于4,
刚刚说obj0按下所以obj_readly_list =(0...001)所以__clz(obj_readly_list)就等于31,所以lv_trigger_bit= 31-31等于0。
最后使用switch来判定对象执行的代码。
|