Echo-Mate 源码学习 1.3lvgl的对象相关概念
之前的裁剪只是为了让大家对lvgl的便利性有一个初步了解,这里开始解释lvgl相关的一些最小组件,也就是对象或者说控件。
首先从屏幕的概念开始,屏幕一般指我们电脑上的物理屏幕,但对于lvgl有其他定义,一般被称为display。
而在display中还需要分出三种优先级,系统级(sys)>顶层(top)>活跃层(active)。
对于这三个优先级的理解,我们可以看出鼠标优先级是系统级别,当我们使用windows电脑安装一些应用时,会弹出一个提示窗告诉我们有东西正在试图修改...要求我们给管理员权限,如下图,当这个弹窗出现的时候,其他背景内容全部虚化且无法使用,这也是系统级。而当我们创建窗口时,同等级的窗口按照后创建盖在新创建的窗口之上的规则,而不论先后,优先级大的会盖在最上面。

在这个例子中还可以体现父类和子类的概念,我们对于类的理解就完全可以当作是一个在屏幕中的方框,只不过父类可能是大框,而子类只是大框中的一个框。

以博主的这个界面为例子,可以把红框理解成一个父类(这里先不纠结代码中具体情况,只是一个比喻),那么画了黄色弧度边框的实际界面可以是红框的一个子类,而内部的一个黄框图标则可以是子类的一个子类,也就成了孙子类。对于这样的类,一般都会定义其属性,属性包含了边框线粗细颜色,代码为了图省事,我就直接用韦东山的例子,不搞项目中的示例了。
lv_obj_t * parent = lv_obj_create(lv_scr_act()); /*创建父类*/
lv_obj_set_size(parent, 100, 80); /*设置x方向和y方向的大小上限*/
lv_obj_t * obj1 = lv_obj_create(parent); /*创建子类*/
lv_obj_set_pos(obj1, 10, 10); /*设置x方向和y方向的大小上限*/
这样就完成了,当然也可以看到,这里创建的parent实际上是lv_scr_act()这个的子类,可以把lv_scr_act()理解成为下图中灰色的底板。

这里补充一个性质,所有的子类都无法超越自己父类的框,且子类的坐标系建立以父类为准,因此当我们移动父类的坐标位置,子类也会跟着走,如下图的绿色框。

lv_obj_set_pos(parent, 50, 50); /*父类的x和y各偏移50像素*/
可以看到褐色的子类跟着绿色的父类一起偏移了,而子类与父类之间存在一定的间隔,我们称之为填充(padding),如果通过相关的设置函数,可以把填充设置成0,对应的也就没有间隔了。
lv_style_set_pad_all(lv_style_t *style, lv_coord_t value); /*例如这个函数,参数选择对象,x填充,y填充*/
其中还会有border和outline这俩比较常用,这里的border也可以理解为和pad差不多的一种,不过是从自己的空间中扣位置出来,而pad是留出与父类之间的空间,outline则是一个边框线,就比如我们鼠标点击桌面图标后会出现的最外围的一个灰色框线。这里代码加图片解释一下border。
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_BLUE)); // 颜色:蓝色
lv_style_set_border_width(&style, 5); // 粗细
lv_style_set_border_opa(&style, LV_OPA_50);
lv_style_set_border_side(&style, LV_BORDER_SIDE_BOTTOM | LV_BORDER_SIDE_RIGHT); // 位置:底部和右边
/*Create an object with the new style*/
lv_obj_t * obj = lv_obj_create(lv_scr_act()); // 创建对象框
lv_obj_add_style(obj, &style, 0); // 应用上面设置的style

这里的学习基本上可以看出,lvgl相关的代码是非常移动的,只要能看懂英文单词,在了解基本概念的前提下,就能够理解是什么作用。
再往下就是事件相关的定义,这个类似于在嵌入式裸机开发中的中断事件,在我们软件端看来就是鼠标点击了一个框,那么要做出的相应操作(这玩意儿在嵌入式中一般叫回调函数)。这最好理解的就是你正在阅读的当前页面,当你使用鼠标滚轮或者点击右侧可以拖拽的长条时,页面会随之移动。一般来说会有以下这些事件:

这里就不得不提前引入label的概念,就把他当作是一个框的文本说明就可以了,事件的代码基本如下:
lv_obj_t * obj = lv_obj_create(lv_scr_act()); // 创建类
lv_obj_t * label = lv_label_create(lv_scr_act()); // 这个类的说明
lv_label_set_text(label, "Button"); // 是个按钮
lv_obj_center(label); // 和父类中心对齐
lv_obj_add_event_cb(obj, my_event_cb, LV_EVENT_ALL, label); // 放入对应的回调函数,label一栏可以为NULL
//这里的LV_EVENT_ALL可以改成上图中特定的动作,ALL则是所有动作都出发这个回调函数
那么可能有人会议或为啥要label,因为label有可能在回调函数中用到,如果用到了比如要改个字,那就可以通过lv_event_get_user_data(e)得到label对应的指针(这里的e是进行了上图中的哪个操作就是哪个宏),改了指针指向的指就可以改变对应的内容,需要关联obj也是一个道理,实际上就是给用户一个反馈,比如一个电灯开关,上面的label写个当前状态off,点一下变成on,就是回调函数中读取了这个label的指针并改变了指向空间的值,至于obj的应用,实际上就可以插入一个开关的动画,点一下就触发一次变化的动画。
这里对于对应操作的处理则是在1.1章节的while循环中的lv_timer_handler();函数会自主安排进行。
小结一下:
对象:直接理解为一个框就行,创建对象的函数中的参数填写父类,优先级根据创建辈分最大对象的参数来决定,如下:
lv_scr_act(); // 活跃层
lv_layer_top(); // 顶层
lv_layer_sys(); // 系统层
属性:定义一个对象的长款位置相关信息,这里需要注意坐标系和我们上学时画的不太一样,上学时候原点在左下角,现在是在左上角。
样式:这玩意儿就是定义框的边框、填充等信息,会涵盖这些内容的颜色,大小等特点。
事件:就是一个能够选择什么操作触发什么函数的东西,比如我们点击项目中的AI,那就会触发打开Echo的动画界面,后台尝试去连接电脑上的server端口这一些列操作。
这样是不是基本就明白了,lvgl其实就是搭积木,选好位置和样式,一个界面的大致轮廓就完成了。
浙公网安备 33010602011771号