如何得知对象的状态发生改变,需要重新绘制?
event的开始
在LVGL中,`lv_obj_send_event` 函数是一个用于发送事件到指定对象的函数。这个函数的调用意味着事件传递机制的开始,它是LVGL事件系统的核心部分,用于在不同组件之间传递消息和信号。当一个对象( 比如按钮、滑块、文本框等)发生了某种状态的改变(例如,被点击、值改变等),`lv_obj_send_event` 函数就会被用来发送一个事件。这个事件会被发送到对象本身,以及可能的父对象。
这个函数的调用通常意味着以下几个方面:
1. **状态改变通知**:当用户与界面交互或者界面内部状态发生变化时,`lv_obj_send_event` 函数会发送一个事件,通知其他部分代码这个改变。
2. **事件传递**:事件会按照一定的顺序传递给注册的回调函数。这些回调函数可以是用户自定义的,用于处理特定类型的事件。
3. **响应链**:事件的发送启动了一个响应链,这个链条上的每个环节都有机会处理这个事件。如果当前对象的回调没有处理这个事件,它会被传递到父对象,直到被处理或者到达响应链的顶端。
4. **用户自定义事件处理**:用户可以注册自己的事件回调函数,用于处理特定对象发送的事件。这样,当`lv_obj_send_event` 被调用时,用户的回调函数会被触发,执行相应的逻辑。
5. **界面更新**:事件的发送有时也会导致界面的更新。例如,当一个对象的尺寸发生变化时,发送的事件可能会触发重绘,以反映新的界面状态。
`lv_obj_send_event` 函数的调用是LVGL中事件驱动模型的一个关键环节,它确保了用户交互和内部状态变化能够被正确地传递和响应。通过这个机制,开发者可以创建动态、响应式的图形用户界面。
event的核心
event_send_core
函数是事件系统的核心函数,它的主要作用是处理和分发事件到相应的对象和回调函数。这个函数是LVGL事件处理机制的心脏,确保了事件能够从源头传递到目标对象,并且允许用户定义的处理函数得以执行。
以下是event_send_core
函数的主要作用:
事件创建:当界面中的某个对象(如按钮、列表、图表等)发生状态变化时,
event_send_core
会创建一个事件对象,这个对象包含了事件的类型、相关的数据以及发生事件的对象等信息。事件分发:
event_send_core
负责将创建的事件对象分发给正确的目标对象。这通常是通过遍历对象的父级链表来完成的,直到找到合适的处理者或者到达顶级父对象。回调执行:当事件被分发到目标对象时,
event_send_core
会检查该对象是否有注册的回调函数来处理该类型的事件。如果有,它会调用这些回调函数,允许用户定义的代码来响应事件。事件传播:事件可以在对象树中向上传播,直到找到处理事件的回调或者到达根级别。这种机制允许在不同层级上响应事件,提供了灵活的事件处理策略。
响应抑制:在某些情况下,一个事件可能被一个对象处理后不再需要向上传播。
event_send_core
允许在回调函数中标记事件为已处理,这样事件就不会继续传播到更高层级的对象。错误处理:如果在事件分发过程中出现错误,如找不到处理函数或者回调函数执行出错,
event_send_core
会负责处理这些错误情况,确保系统的稳定性。性能优化:
event_send_core
通过智能的事件分发机制,确保只有相关的对象和回调函数被触发,从而提高事件处理的效率和性能。
从事件通知到渲染完成,整个过程做了哪些工作?
从事件通知到事件处理完成,完成渲染任务的整个函数调用过程如下:
绘制开始啦!!!
1.lv_obj_send_event(lv_obj_t * obj, lv_event_code_t event_code, void * param)
用于向指定的对象发送事件。事件可以是用户定义的自定义事件,由event_send_core处理接下来的事情
2.event_send_core
其函数实现核心是:lv_event_send(list, e, true)-->lv_obj_event_base--->lv_event_send(list, e, false)
这样一个流程之后,开始对该obj的父对象进行同样的处理,直到没有可以处理的父对象。3.lv_obj_event_base(const lv_obj_class_t * class_p, lv_event_t * e)
调用event_cb,处理事件,event_cb有两个类型,一个是class类型注册回调,一个是具体obj注册的回调函数(lv_obj_add_event_cb)4.lv_obj_event就是class 类型的event_cb,在初始化的时候配置。
lv_obj_add_event_cb函数则是后面根据需要注册具体的回调,lv_event_add(&obj->spec_attr->event_list, event_cb, filter, user_data);5.lv_obj_redraw(lv_layer_t * layer, lv_obj_t * obj)
从lv_event_t中拿到需要绘制的obj对象,得到需要重新绘制obj的哪些区域、背景色、source image等信息(lv_obj_init_draw_rect_dsc)6.lv_draw_rect(lv_layer_t * layer, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
针对layer,开始进行绘制。
lv_draw_add_task(lv_layer_t * layer, const lv_area_t * coords)函数就是将要绘制的区域信息和layer的裁剪区域通过new task 联系起来(填充一个绘制task),然后加到队列里面去。7.lv_draw_finalize_task_creation(lv_layer_t * layer, lv_draw_task_t * t)
创建和配置绘制任务时需要调用。 它将向小部件发送有关新绘制任务的事件并将其分配给绘制单元8.lv_draw_dispatch:
获取一个显示对象,循环处理该显示对象的layer(lv_draw_dispatch_layer(disp, layer));
尝试获得一个绘制layer的任务,通过lv_draw_dispatch_layer进行分派.9.lv_draw_dispatch_layer(lv_display_t * disp, lv_layer_t * layer)
内部用于尝试调度具体层的绘制任务,两个入参分别是显示对象和需要绘制的layer。
首先,会移除已经完成的task;
然后,判断该层已准备就绪,启用混合其缓冲区,
当该图层是src,找到一个类型为TYPE_LAYER的绘制任务;(当执行类型为 `LV_DRAW_TASK_TYPE_LAYER` 的绘图任务时,LittlevGL 将指定图层的内容渲染到屏幕上。)找到一个不忙且至少可以完成一项任务的绘图单元.10.最终调用dispatch_cb进行具体的绘制
11.dispatch_cb由初始化的时候注册实际的处理函数draw_dispatch
12.draw_dispatch函数,layer->draw_buf->data是layer中的target buffer(line205)
13.lv_vg_lite_buffer_from_draw_buf,将layer层的targetbuffer给到draw_uint
lv_vg_lite_buffer_from_draw_buf(&u->target_buffer, layer->draw_buf);14.然后就可以根据task->type,调用对应的绘制函数。
15.以贴图为例子,lv_draw_vg_lite_img
16.首先,会对绘制需求(task->draw_dsc)进行处理解析,解码出要贴的source image。(lv_vg_lite_buffer_open_image)
17.然后进行底层贴图的驱动调用,进行贴图操作。
备注
第13点中,隐含着如下信息
从u->task_act->draw_dsc解码出src_buf(lv_vg_lite_buffer_open_image);
u->base_unit.target_layer->draw_buf->data就是target buffer.
layer里面包含了target buffer 和 area信息
task 里面可以解析出source image数据、area信息。
在第12点中,通过下面的code将task和layer联系在一起
u->base_unit.target_layer = layer;
u->base_unit.clip_area = &t->clip_area;
u->task_act = t;
is_independent(lv_layer_t * layer, lv_draw_task_t * t_check)
查找排队且独立的任务,根据area判断layer中的task和t_check是否有相交的地方,明确是否是独立的task.
重要的枚举
LV_DRAW_TASK_STATE_WAITING:表示绘图任务正在等待某些操作完成,例如正在等待图层渲染完成。
LV_DRAW_TASK_STATE_QUEUED:表示绘图任务已经被添加到绘图队列中,等待系统调度执行。
LV_DRAW_TASK_STATE_IN_PROGRESS:表示绘图任务正在执行中。
LV_DRAW_TASK_STATE_READY:表示绘图任务已经准备好执行,等待系统调度执行。
这些是LVGL中的绘图任务类型,用于指定要绘制的图形类型。具体含义如下:
- LV_DRAW_TASK_TYPE_FILL:填充矩形或圆形
- LV_DRAW_TASK_TYPE_BORDER:绘制矩形或圆形的边框
- LV_DRAW_TASK_TYPE_BOX_SHADOW:绘制矩形或圆形的阴影
- LV_DRAW_TASK_TYPE_LABEL:绘制文本标签
- LV_DRAW_TASK_TYPE_IMAGE:绘制图像
- LV_DRAW_TASK_TYPE_LAYER:绘制图层
- LV_DRAW_TASK_TYPE_LINE:绘制直线
- LV_DRAW_TASK_TYPE_ARC:绘制弧线
- LV_DRAW_TASK_TYPE_TRIANGLE:绘制三角形
- LV_DRAW_TASK_TYPE_MASK_RECTANGLE:绘制矩形遮罩
- LV_DRAW_TASK_TYPE_MASK_BITMAP:绘制位图遮罩
- LV_DRAW_TASK_TYPE_VECTOR:绘制矢量图形
LVGL使用这些任务类型来绘制各种UI元素,例如按钮、文本框、进度条等。开发人员可以使用LVGL提供的API来创建和定制这些UI元素。