ITPub博客

首页 > 嵌入式/内核开发 > 嵌入式/内核开发 > 《LVGL开发指南 V1.0(G4电机开发板专用)》第七章 基础对象(lv_obj)

《LVGL开发指南 V1.0(G4电机开发板专用)》第七章 基础对象(lv_obj)

原创 嵌入式/内核开发 作者:正点原子 时间:2026-05-22 10:48:16 0 删除 编辑

第七章 基础对象(lv_obj)


       基础对象本身就是一个小部件,当它被创建出来之后,其呈现出一个矩形。除此之外,基础对象还是其他小部件的父类,所有部件的位置、大小等基本属性都是归基础对象管理的。

       本章节将分为以下几个小节:

       7.1 基础对象的作用

       7.2 基础对象的相关知识

       7.3 基础对象的API函数

       7.4 基础对象部件的实验


        7.1 基础对象的作用

       基础对象的作用有四个:

       ① 管理其他部件的基本属性;

       ② 作为背景装饰;

       ③ 辅助布局;

       ④ 界面切换。

       第一个作用我们在6.2章节中已经介绍过,本章重点介绍基础对象的其他作用。

       1. 作为背景装饰

       当基础对象被创建出来后,它默认是一个圆角矩阵,如图7.1.1所示:


图7.1.1 创建基础对象


       在设计较为复杂的GUI界面时,不同功能的模块之间需要清晰地划分区域,此时,我们可以使用基础对象作为背景,对不同的区域进行划分。

       2. 辅助布局

       当GUI界面中有一些组成内容相似的模块时,可以利用基础对象作为父对象,创建出其他的部件,这些部件将出现在基础对象内部,此时,我们只需要管理各基础对象之间的布局即可,其他的部件会随之变化。辅助布局的示意图如下:


图7.1.2 辅助布局示例


       3. 界面切换

       当基础对象做为父对象,创建出其他的部件时,这些被创建出来的部件将出现在其父对象的内部,换言之,此时的基础对象就是一个容器,它里面子对象会随之移动。在UI设计中,我们可以利用上述的特性,实现界面的切换,示意图如下所示:


图7.1.3 界面切换示意图


       由上图可知,基础对象1、2分别用于管理界面1、2,它们之中存在一些子对象(例如开关),当用户需要切换界面时,只需切换容器即可。

       接下来,我们介绍界面切换的两种实现方法:

       方法一:删除法

       当用户删除一个父对象时,它所有的子对象也会被一并删除,因此,我们需要实现界面的切换,可以调用lv_obj_del函数,直接删除基础对象(父对象),然后再创建新的界面,这样即可实现界面切换,示意图如下所示:


图7.1.4 删除法切换界面


       方法二:隐蔽法

       此方法的原理和删除法类似,只不过这里是将界面隐藏起来,需要的时候还能还原。注意:隐藏的界面并未被删除,其占用内存也没有得到释放,因此,当用户使用此方法切换界面时,需要考虑内存溢出的隐患。隐蔽法的示意图如下所示:


图7.1.5 隐蔽法切换界面


       由上图可知,隐藏法的实现逻辑如下:先创建出不同的界面,然后调用lv_obj_add_flag函数,为指定的界面添加隐藏的标志,此时,该界面将隐藏,而当我们需要显示某个界面时,只需要调用lv_obj_clear_flag函数,清除隐藏属性即可。注意:不要同时清除多个界面的隐藏属性,否则可能出现显示混乱的问题。下面我们来看一下上述的两个函数:

       lv_obj_add_flag函数

       设置一个或多个标志,其函数原型如下所示:

void lv_obj_add_flag(lv_obj_t *obj, lv_obj_flag_t f);

       该函数的形参,如表7.1.1所示:


表7.1.1 lv_obj_add_flag函数形参描述


       返回值:无。

       2. lv_obj_clear_flag函数

       清除一个或多个标志,其函数原型如下所示:

void lv_obj_clear_flag(lv_obj_t *obj, lv_obj_flag_t f);

       该函数的形参,如表7.1.2所示:


表7.1.2 lv_obj_clear_flag函数形参描述


       返回值:无。

       在LVGL中,标志相关的枚举如下源码所示:

enum {
    LV_OBJ_FLAG_HIDDEN          = (1L << 0),  /* 隐藏 */
    LV_OBJ_FLAG_CLICKABLE       = (1L << 1),
    LV_OBJ_FLAG_CLICK_FOCUSABLE = (1L << 2),
    LV_OBJ_FLAG_CHECKABLE       = (1L << 3),
    LV_OBJ_FLAG_SCROLLABLE      = (1L << 4),
    LV_OBJ_FLAG_SCROLL_ELASTIC  = (1L << 5),
    LV_OBJ_FLAG_SCROLL_MOMENTUM = (1L << 6),
    LV_OBJ_FLAG_SCROLL_ONE      = (1L << 7),
    LV_OBJ_FLAG_SCROLL_CHAIN_HOR = (1L << 8),
    LV_OBJ_FLAG_SCROLL_CHAIN_VER = (1L << 9),
LV_OBJ_FLAG_SCROLL_CHAIN     = (LV_OBJ_FLAG_SCROLL_CHAIN_HOR |
                                    LV_OBJ_FLAG_SCROLL_CHAIN_VER),
    LV_OBJ_FLAG_SCROLL_ON_FOCUS = (1L << 10),
    LV_OBJ_FLAG_SCROLL_WITH_ARROW  = (1L << 11),
    LV_OBJ_FLAG_SNAPPABLE       = (1L << 12),
    LV_OBJ_FLAG_PRESS_LOCK      = (1L << 13),
    LV_OBJ_FLAG_EVENT_BUBBLE    = (1L << 14),
    LV_OBJ_FLAG_GESTURE_BUBBLE  = (1L << 15),
    LV_OBJ_FLAG_ADV_HITTEST     = (1L << 16),
    LV_OBJ_FLAG_IGNORE_LAYOUT   = (1L << 17),
    LV_OBJ_FLAG_FLOATING        = (1L << 18),
    LV_OBJ_FLAG_OVERFLOW_VISIBLE = (1L << 19),
 
    LV_OBJ_FLAG_LAYOUT_1        = (1L << 23),
    LV_OBJ_FLAG_LAYOUT_2        = (1L << 24),
 
    LV_OBJ_FLAG_WIDGET_1        = (1L << 25),
    LV_OBJ_FLAG_WIDGET_2        = (1L << 26),
    LV_OBJ_FLAG_USER_1          = (1L << 27),
    LV_OBJ_FLAG_USER_2          = (1L << 28),
    LV_OBJ_FLAG_USER_3          = (1L << 29),
    LV_OBJ_FLAG_USER_4          = (1L << 30),
};


        7.2 基础对象的相关知识

       基础对象的大部分知识,我们在6.2章节已经介绍过了,这里我们只介绍一个拓展的内容:扩大点击区域。

       在默认的情况下,用户必须要在区域边界内点击对象,这样才能成功触发事件(例如按下)。如果我们想扩展点击区域,可以调用lv_obj_set_ext_click_area函数来设置,其函数原型如下所示:

void lv_obj_set_ext_click_area(lv_obj_t *obj, lv_coord_t size);

       该函数的形参,如表7.2.1所示:


表7.2.1 lv_obj_set_ext_click_area函数形参描述


       返回值:无。


        7.3 基础对象的API函数

       LVGL官方提供了很多与基础对象相关API函数,如表7.3.1所示:


表7.3.1 基础对象相关API函数


       接下来,我们介绍LVGL基础对象常用的API函数:

       1. lv_obj_create 函数

       创建基础对象,其函数原型如下所示:

lv_obj_t *lv_obj_create(lv_obj_t *parent);

       该函数的形参,如表7.3.2所示:


表7.3.2 lv_obj_create函数形参描述


       返回值:返回对象控制块。

       2. lv_obj_get_state函数

       获取对象的状态,其函数原型如下所示:

lv_state_t lv_obj_get_state(const lv_obj_t *obj);

       该函数的形参,如表7.3.3所示:


表7.3.3 lv_obj_get_state函数形参描述


       返回值:返回对象状态。


        7.4 基础对象部件的实验


       7.4.1 硬件设计

       1. 例程功能

       本实验主要测试基础对象API函数的使用,实验现象:开机后,显示两个矩形,用户可以通过KEY0、KEY1切换当前选中的矩形,当按下大矩形的时候,会改变其位置,小矩形位置也随之改变,当按下小矩形的时候,小矩形的位置会改变,其超出大矩形的部分将不可见。与此同时,LED0闪烁,提示系统正在运行。

       该实验的完整源码,请参考《LVGL例程4 lv_obj(基础对象)》例程,路径:A盘→4,程序源码 →3,扩展例程 →3,LVGL例程。


       7.4.2 软件设计


       7.4.2.1 程序流程图

       本实验的程序流程图,如下图7.4.2.1.1所示:


图7.4.2.1.1 基础对象实验流程图


       7.4.2.2 程序解析

       关于LVGL的用户代码,我们都是在lv_mainstart.c文件中编写的,本实验的源码如下所示:

/**************************** 第一部分 开始 ****************************/
/**
 * @brief  LVGL演示
 * @param  无
 * @return 无
 */
void lv_mainstart(void)
{
/* 创建“组” */
    lv_group_t *g = lv_group_create();
    lv_indev_set_group(indev_keypad, g);
    
    /* 动态获取屏幕大小 */
    scr_act_width = lv_obj_get_width(lv_scr_act());    /* 获取活动屏幕的宽度 */
    scr_act_height = lv_obj_get_height(lv_scr_act());  /* 获取活动屏幕的高度 */
 
    /* 父对象 */
parent_obj = lv_obj_create(lv_scr_act());           /* 创建父对象 */
/* 设置父对象的大小 */
lv_obj_set_size(parent_obj, scr_act_width * 2/3, scr_act_height * 2/3);
/* 设置父对象的位置:顶部居中 */ 
lv_obj_align(parent_obj, LV_ALIGN_TOP_MID, 0, 0);  
/* 设置父对象的背景色:浅蓝色 */
lv_obj_set_style_bg_color(parent_obj, lv_color_hex(0x99ccff), 0); 
/* 设置父对象被聚焦时的轮廓宽度 */
lv_obj_set_style_shadow_width(parent_obj, 10, LV_STATE_FOCUSED);  
/* 为父对象添加事件:按下释放后触发 */ 
    lv_obj_add_event_cb(parent_obj, obj_event_cb, LV_EVENT_CLICKED, NULL); 
 
    /* 子对象 */
child_obj = lv_obj_create(parent_obj);             /* 创建子对象 */
/* 设置子对象的大小 */
lv_obj_set_size(child_obj, scr_act_width / 3, scr_act_height / 3);   
/* 设置子对象的位置:居中 */
lv_obj_align(child_obj, LV_ALIGN_CENTER, 0, 0);    
/* 设置子对象的背景色:深蓝色 */  
lv_obj_set_style_bg_color(child_obj, lv_color_hex(0x003366), 0);  
/* 设置子对象被聚焦时的轮廓宽度 */
lv_obj_set_style_shadow_width(child_obj, 10, LV_STATE_FOCUSED); 
/* 为子对象添加事件:按下释放后触发 */ 
    lv_obj_add_event_cb(child_obj, obj_event_cb, LV_EVENT_CLICKED, NULL);  
    
/* 添加部件到“组” */
    lv_group_add_obj(g, parent_obj);
    lv_group_add_obj(g, child_obj);
}
/**************************** 第一部分 结束 ****************************/
 
/**************************** 第二部分 开始 ****************************/
/**
 * @brief  基础对象事件回调
 * @param  *e :事件相关参数的集合,它包含了该事件的所有数据
 * @return 无
 */
static void obj_event_cb(lv_event_t *e)
{
    lv_obj_t *target = lv_event_get_target(e);     /* 获取事件触发源 */
 
    if (target == parent_obj)                      /* 判断触发源:是不是父对象? */
{
/* 重新设置父对象的位置:居中 */
        lv_obj_align(parent_obj, LV_ALIGN_CENTER, 0, 0);  
    }
    else if (target == child_obj)                 /* 判断触发源:是不是子对象? */
{
/* 重新设置子对象的位置:右侧居中,再向X轴偏移100 */
        lv_obj_align(child_obj, LV_ALIGN_RIGHT_MID, 50, 0);    
    }
}
/**************************** 第二部分 结束 ****************************/

       上述源码可分为以下两个部分:

       ① 创建对象并添加事件回调。我们首先获取动态屏幕的大小,以适配不同尺寸的屏幕,然后再分别创建父对象和子对象,并为它们添加事件回调。注意:因为我们用的是按键控制GUI,因此需要创建“组”,并将部件添加到“组”当中(某些部件默认在组中,不需要添加),这样才能成功控制部件。

       ② 处理事件回调。在回调函数中,我们首先获取事件的触发源,然后判断是父对象还是子对象触发的事件,若是前者,则重新设置父对象的位置,使其居中对齐,此时,子对象的位置也会随之变化;若是后者,则重新设置子对象的位置,使其右侧居中,并且向X轴的正半轴偏移100像素,此时,子对象超出父对象的部分默认不可见。


       7.4.3 下载验证

       把工程编译并下载到我们的开发板中,运行效果如图7.4.3.1所示:


图7.4.3.1 基础对象例程演示

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70040860/viewspace-3171881/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2024-08-30

  • 博文量
    588
  • 访问量
    764146