【LVGL】对象

对象的概念

  • LVGL是采用面向对象的编程思想(OOP),她的基本构造块(类)是对象的实例。每个部件都是一个对象的实例,如Button、Label等。
  • 在LVGL中,lv_obj_t(类)定义了部件的抽象特点,其定义包含了数据的形式以及对数据的操作。部件子类比原本的类(父类或基类)要更加具体化,子类会继承父类的属性和行为。
  • 在LVGL中所有的对象都在lv_obj_t这个结构体的基础上进行演变,所以我们就看到了各种不一样的部件。计算是一样的部件,继承父类后演变出来的对象形态、风格样式也是不一样的。
  • 因为lvgl是使用C语言编写的,因此lv_obj_t只能通过结构体来表示,并不是一个实例化后的类。因此我们需要先实例化出一个父类,所有的部件都是继承这个父类的,这个父类就是基础对象(lv_obj)。

LVGL中的基础对象

  • 在lvgl中所有对象都有一个共同的父类,这个父类就是基础对象。所有的类都是直接或者间接继承这个基础对象的。
  • lvgl中的基础对象就是lv_obj,这个基础对象有2个作用:一是作为所有部件的父类,二是作为屏幕显示的对象(屏幕是没有父类的基础对象)。
  • 在lvgl中获取基础对象的方式是lv_scr_act()。这个基础对象是在main函数中的lv_init()被初始化的。
  • 一般一个屏幕对象分为3层:用户层、顶层、系统层。
    • 用户层(lv_scr_act(void))一般我们操作的都是用户层
    • 顶层(lv_layer_top(void))是用来做出一些响应的,如按键后弹出一个对话框。
    • 系统层(lv_layer_sys(void))一般是不受任何界面对象限制的,如鼠标可以在界面任意位置移动,鼠标就是在系统层。

屏幕对象的创建过程

  1. lv_init()中的_lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t));初始化显示器的链表
  2. 在lv_disp_drv_register中的_lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll);注册显示器到链表,并且在显示器上创建一个默认屏幕disp->act_scr=lv_obj_create(NULL);

基础对象的大小(size)

  • 调整基础对象的大小
    • 设置宽度:lv_obj_set_width(obj, new_width)
    • 设置高度:lv_obj_set_height(obj, new_height)
    • 同时设置宽度和高度:lv_obj_set_size(obj, new_width, new_height)
  • 获取基础对象的大小
    • 获取宽度:lv_obj_get_width(obj)
    • 获取高度:lv_obj_get_height(obj)

基础对象的位置(position)

  • 在lvgl中位置是相对屏幕的位置。

  • 在现实生活中,我们所说的原点,一般是指“笛卡尔坐标系”,也叫做直角坐标系,就是我们数学中使用的坐标系,它的原点在左下角,y轴自下而上,x轴自左向右。而在屏幕中我们使用的是“lcd坐标系”,它的原点是在左上角,y轴是自上而下的,x轴自左向右。

  • 只要确定了原点,我们就可以按照坐标系,确定部件的位置。

  • 设置基础对象的位置
    (注意:设置的x或者y支持设置负值,显示效果会是超过屏幕的边界,只显示可显示的区域)

    • 设置x轴位置:lv_obj_set_x(obj, new_x)
    • 设置y轴位置:lv_obj_set_y(obj, new_y)
    • 同时设置x和y的位置:lv_obj_set_pos(obj, new_x, new_y)
  • 设置基础对象的对齐(Alignment)
    如果每个部件都需要准确计算具体的坐标位置,有时间会太麻烦。lvgl提供了对齐的表示方式

    • 参照父对象对齐:lv_obj_set_align(obj, LV_ALIGN_...)
    • 参照父对象对齐后再设置坐标位置:lv_obj_align(obj, LV_ALIGN_..., x, y)
    • 参照另一个对象(无父子关系)对齐后再设置坐标位置:lv_obj_align_to(obj_to_align, obj_referece, LV_ALIGN_..., x, y)
  • 获取基础对象的位置

    • 获取x轴位置:lv_obj_get_x(obj)
    • 获取y轴位置:lv_obj_get_y(obj)

基础对象的盒子模型(border-box)

lvgl遵循CSS的border-box模型,对象的盒子由以下部分组成:

  • 边界(dounding):元素的宽度和高度围起来的区域(整个盒子)
  • 边框(border):边框有大小和颜色等属性(相当于盒子的厚度和它的颜色)
  • 填充(padding):对象两侧与其子对象之间的空间(盒子的填充物)
  • 内容(content):如果边界框
  • 轮廓(outline):lvgl中没有外边距(margin)的概念(盒子与其他盒子之间的距离),取而代之的是轮廓outline。它是绘制于元素(盒子)周围的一条线,不占据内部空间,位于边框边缘外围。

基础对象的样式(style)

普通样式

样式就是用名称保存下来的,对修饰对象进行修饰所使用的一组修饰参数

  • 样式初始化:要使用样式,必须先初始化样式。在lvgl中,样式是储存在lv_style_t变量中的。样式变量应该是静态的、全局或动态分配的。不能是局部变量,因为函数结束时会被销毁。
static lv_style_t style_obj;
lv_style_init(&style_obj);
  • 设置样式的属性:设置样式属性的函数接口的格式:lv_style_set_<property_name>(&style, <value>),例如:
/* 设置背景色 */
lv_style_set_bg_color(&style_obj,lv_color_hex(0x000000);
/* 设置背景透明度 */
lv_style_set_bg_opa(&style_obj, LV_OPA_50);
  • 添加样式到对象:当我们初始化并设置好一个样式后,就可以将其应用到对象上。接口函数是lv_obj_add_style(obj, &style, <selector>),selector是添加样式的部分和状态的OR-ed值(不能是互斥,否则就是清除标志,没法合并),示例:
/* 默认(常用) */
lv_obj_add_style(obj, &style_obj, 0);
/* 在对象被按下时应用样式 */
lv_obj_add_style(obj, &style_obj, LV_STATE_PRESSED);
  • 我们可以给一个控件的不同部分别分设置样式,也可以将同一个样式设置给不同的对象。
  • 我们可以对控件整体设置样式,也支持对部分进行设置。
    对象可以有部分(parts),他们也可以有自己的样式,LVGL中存在以下预定义的部分:
名称描述
LV_PART_MAIN类似矩形的背景
LV_PART_SCROLLBAR滚动条
LV_PART_INDICATOR指示,例如用于滑块、条、开关或者复选框的勾选框
LV_PART_KNOB像手柄一样可以抓取的调整值
LV_PART_SELECTED表示当前选择的选项和部分
LV_PART_ITEMS如果小部件

本地样式

  • 除了普通样式,对象还可以存储本地样式
  • 本地样式和普通样式类似,但是不能和其他对象共享。
  • 如果使用本地样式,将自动分配局部样式,并在对象删除时释放。
  • 本地样式对于向对象添加本地自定义很有用。
  • 如果同时定义了本地样式和普通样式,本地样式的优先级更高。

本地样式的接口函数:lv_obj_set_style_local_<property_name>(obj, <value>, <selector>);
示例:

/* 设置背景色 */
lv_obj_set_style_bg_color(obj,lv_color_hex(0xffff),0);
/* 设置背景透明度 */
lv_obj_set_style_bg_opa(obj,LV_OPA_50,0);

样式继承

如果父类设置了样式的属性,一个子类继承父类后,也继承了父类的样式。

基础对象的事件(events)

添加事件

lv_obj_add_event_cb(obj, event_cb, event_code, user_data);

event_cb是触发事件的回调函数
event_code(事件类型,指的是什么操作下会执行回调函数),可以在这里指明回调的操作,也可以在这里指明LV_EVENT_ALL所有事件,在回调函数里根据事件处理相应的内容。
一般的事件类型可以分为以下这几类:
输入设备事件(Input device events)
绘图事件(Drawing events)
其他事件(Special events)
特殊事件(Other events)
自定义事件(Custom events)

示例
static void btn_event_cb(lv_event_t* e)
{
    /* 通过code获取触发事件的类型 */
    lv_event_code_t code = lv_event_get_code(e);

    /* 在回调函数里可以通过target,获取触发这个事件的对象 */
    lv_obj_t* btn = lv_event_get_target(e);
    /* 通过对象获取参数 */
    lv_obj_t* obj = (lv_obj_t*)lv_event_get_user_data(e);

    if (code == LV_EVENT_CLICKED)
    {
        static uint8_t cnt = 0;
        cnt++;

        /* 获取触发源对象的第一个子对象 */
        lv_obj_t* label = lv_obj_get_child(btn, 0);
        lv_label_set_text_fmt(label, "Button:%d", cnt);

        lv_obj_set_style_bg_color(obj, lv_color_hex(0x000000), 0);
    }
}

void login_page(void)
{

    lv_obj_t* btn = lv_btn_create(lv_scr_act());
    lv_obj_set_pos(btn, 10, 10);
    lv_obj_set_size(btn, 120, 50);
    printf("obj width is %d\r\n", lv_obj_get_width(btn));

    lv_obj_set_align(btn, LV_ALIGN_CENTER);
    lv_obj_align(btn, LV_ALIGN_CENTER, 0, 100);
    

    lv_obj_t* label = lv_label_create(btn);
    lv_label_set_text(label, "Button");
    lv_obj_center(label);

    lv_obj_align_to(label, btn, LV_ALIGN_CENTER, 5, 5);

    lv_obj_t* obj = lv_obj_create(lv_scr_act());
    lv_obj_center(obj);

    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, obj);
}

发送事件

lv_event_send(obj, event_cb, event_code, user_data);

删除事件

删除事件,可以使用对象+回调函数确定删除的对象,也可以在添加事件时,保存添加返回的指针对象,用这个指针对象来删除事件。

lv_obj_remove_event_cb(obj, event_cb);
/* event_dsc是lv_obj_add_event_cb返回的指针 */
lv_obj_remove_event_dsc(obj, event_dsc);

事件回调函数的lv_event_t参数

事件回调只有一个参数对象,通过这个参数对象,我们可以获取很多和对象关联的对象:

  • 获取触发的事件源:
    lv_event_code_t code = lv_event_get_code(e);
  • 获取触发事件的对象:
    lv_obj_t* targe = lv_event_get_target(e);
  • 获取最初触发事件的对象(事件冒泡)
    lv_obj_t* target = lv_event_get_current_target(e);
  • 获取事件传递的用户数据:
	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_target(e);获取触发事件的当前对象。
lv_event_get_current_target(e);获取触发事件的冒泡的父对象。(如果父对象也启用,层层递推,拿到的是最顶级的父对象)。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值