2 Star 3 Fork 1

稀风/LVGL

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
基础对象-lv_obj.md 10.91 KB
一键复制 编辑 原始数据 按行查看 历史
稀风 提交于 2024-03-31 20:37 . update

基础对象

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

基础对象的作用

  • 基础对象的作用有四个:
    • 管理其他部件的基本属性;
    • 作为背景装饰;
    • 辅助布局;
    • 界面切换。

作为背景装饰

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

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

辅助布局

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

界面切换

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

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

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

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

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

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

lv_obj_add_flag & lv_obj_clear_flag

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

    void lv_obj_add_flag(lv_obj_t *obj, lv_obj_flag_t f);
  • 该函数的形参,如下表所示:

    参数 描述
    obj 指向对象的指针
    f 标志相关枚举
  • 清除一个或多个标志,其函数原型如下所示:

    void lv_obj_clear_flag(lv_obj_t *obj, lv_obj_flag_t f);
  • 该函数的形参,如下表所示:

    参数 描述
    obj 指向对象的指针
    f 标志相关枚举
  • 在 LVGL 中,标志相关的枚举如下源码所示:

    typedef enum {
        LV_OBJ_FLAG_HIDDEN          = (1L << 0),  /*隐藏*< Make the object hidden. (Like it wasn't there at all)  */
        LV_OBJ_FLAG_CLICKABLE       = (1L << 1),  /**< Make the object clickable by the input devices*/
        LV_OBJ_FLAG_CLICK_FOCUSABLE = (1L << 2),  /**< Add focused state to the object when clicked*/
        LV_OBJ_FLAG_CHECKABLE       = (1L << 3),  /**< Toggle checked state when the object is clicked*/
        LV_OBJ_FLAG_SCROLLABLE      = (1L << 4),  /**< Make the object scrollable*/
        LV_OBJ_FLAG_SCROLL_ELASTIC  = (1L << 5),  /**< Allow scrolling inside but with slower speed*/
        LV_OBJ_FLAG_SCROLL_MOMENTUM = (1L << 6),  /**< Make the object scroll further when "thrown"*/
        LV_OBJ_FLAG_SCROLL_ONE      = (1L << 7),  /**< Allow scrolling only one snappable children*/
        LV_OBJ_FLAG_SCROLL_CHAIN_HOR = (1L << 8), /**< Allow propagating the horizontal scroll to a parent*/
        LV_OBJ_FLAG_SCROLL_CHAIN_VER = (1L << 9), /**< Allow propagating the vertical scroll to a parent*/
        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),  /**< Automatically scroll object to make it visible when   focused*/
        LV_OBJ_FLAG_SCROLL_WITH_ARROW  = (1L << 11), /**< Allow scrolling the focused object with arrow   keys*/
        LV_OBJ_FLAG_SNAPPABLE       = (1L << 12), /**< If scroll snap is enabled on the parent it can snap   to this object*/
        LV_OBJ_FLAG_PRESS_LOCK      = (1L << 13), /**< Keep the object pressed even if the press slid from   the object*/
        LV_OBJ_FLAG_EVENT_BUBBLE    = (1L << 14), /**< Propagate the events to the parent too*/
        LV_OBJ_FLAG_GESTURE_BUBBLE  = (1L << 15), /**< Propagate the gestures to the parent*/
        LV_OBJ_FLAG_ADV_HITTEST     = (1L << 16), /**< Allow performing more accurate hit (click) test. E.  g. consider rounded corners.*/
        LV_OBJ_FLAG_IGNORE_LAYOUT   = (1L << 17), /**< Make the object position-able by the layouts*/
        LV_OBJ_FLAG_FLOATING        = (1L << 18), /**< Do not scroll the object when the parent scrolls and   ignore layout*/
        LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS = (1L << 19), /**< Send `LV_EVENT_DRAW_TASK_ADDED` events*/
        LV_OBJ_FLAG_OVERFLOW_VISIBLE = (1L << 20),/**< Do not clip the children to the parent's ext draw   size*/
    #if LV_USE_FLEX
        LV_OBJ_FLAG_FLEX_IN_NEW_TRACK = (1L << 21),     /**< Start a new flex track on this item*/
    #endif
    
        LV_OBJ_FLAG_LAYOUT_1        = (1L << 23), /**< Custom flag, free to use by layouts*/
        LV_OBJ_FLAG_LAYOUT_2        = (1L << 24), /**< Custom flag, free to use by layouts*/
    
        LV_OBJ_FLAG_WIDGET_1        = (1L << 25), /**< Custom flag, free to use by widget*/
        LV_OBJ_FLAG_WIDGET_2        = (1L << 26), /**< Custom flag, free to use by widget*/
        LV_OBJ_FLAG_USER_1          = (1L << 27), /**< Custom flag, free to use by user*/
        LV_OBJ_FLAG_USER_2          = (1L << 28), /**< Custom flag, free to use by user*/
        LV_OBJ_FLAG_USER_3          = (1L << 29), /**< Custom flag, free to use by user*/
        LV_OBJ_FLAG_USER_4          = (1L << 30), /**< Custom flag, free to use by user*/
    } _lv_obj_flag_t;

基础对象的相关知识

  • 基础对象的大部分知识,我们在 LVGL基础知识 已经介绍过了,这里我们只介绍一个拓展的内容:扩大点击区域。
  • 在默认的情况下,用户必须要在区域边界内点击对象,这样才能成功触发事件(例如按下)。如果我们想扩展点击区域,可以调用 lv_obj_set_ext_click_area 函数来设置,其函数原型如下所示:
    void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t size);
  • 该函数的形参,如下表所示:
    参数 描述
    obj 指向对象的指针
    size 设置点击区域大小

基础对象的 API 函数

  • LVGL 官方提供了很多与基础对象相关 API 函数,如下表所示:
    函数 描述
    lv_obj_create () 创建基础对象(矩形)
    lv_obj_set_user_data() 设置对象的 user_data 字段
    lv_obj_has_flag() 检查是否在对象上设置了指定的标志
    lv_obj_has_flag_any() 检查是否在对象上设置了任何标志
    lv_obj_get_state() 获取对象的状态
    lv_obj_has_state() 检查对象是否处于指定状态
    lv_obj_get_group() 获取对象的组
    lv_obj_get_user_data() 获取对象的用户数据
    lv_obj_allocate_spec_attr() 为对象分配特殊数据(还未分配时)
    lv_obj_check_type() 检查 obj 的类型
    lv_obj_has_class() 检查是否有任何对象具有指定的类
    lv_obj_get_class() 获取对象的类
    lv_obj_is_valid() 检查是否有任何对象在活动

代码实战

  • 创建一个父对象,其宽和高都是屏幕的 2/3,顶部居中,背景色:浅蓝色,代码如下:

    /* 获取当前显示屏幕的宽和高 */
    int32_t  with = lv_obj_get_width(lv_scr_act());
    int32_t  height = lv_obj_get_height(lv_scr_act());
    
    /* 创建一个父对象 */
    parent_obj = lv_obj_create(lv_scr_act());
    /* 设置父对象的大小 - 宽和高都是屏幕的 2/3 */
    lv_obj_set_size(parent_obj, with*2/3, 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);
  • 再创建一个子对象,其宽和高都是屏幕的 1/3,居中,背景色:深蓝色,代码如下:

    /* 创建一个子对象 */
    child_obj = lv_obj_create(parent_obj);
    /* 设置子对象的大小 - 宽和高都是父对象的 1/3 */
    lv_obj_set_size(child_obj, with/3, 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);
  • 为父对象添加事件:长按触发,切换父对象背景颜色为绿色;为子对象添加事件,按下触发,重新设置子对象的位置:右侧居中,再向 X 轴偏移 100。代码实现如下:

    /* 为父对象添加事件:长按触发 */
    lv_obj_add_event_cb(parent_obj, obj_event_cb, LV_EVENT_LONG_PRESSED, NULL);
    /* 为子对象添加事件:按下触发 */
    lv_obj_add_event_cb(child_obj, obj_event_cb, LV_EVENT_CLICKED, NULL);
    
    void obj_event_cb(lv_event_t * e)
    {
        lv_obj_t* target = lv_event_get_target(e); /* 获取事件触发源 */
        {
            if (target == parent_obj) /* 判断触发源:是不是父对象? */
            {
                /* 设置父对象的背景色:绿色 */
                lv_obj_set_style_bg_color(parent_obj, lv_color_hex(0x00FF00), 0);
            }
            else if (target == child_obj) /* 判断触发源:是不是子对象? */
            {
                /* 重新设置子对象的位置:右侧居中,再向 X 轴偏移 100 */
                lv_obj_align(child_obj, LV_ALIGN_RIGHT_MID, 100, 0);
            }
        }
    }
  • 完整代码见:Demo_lv_obj.c

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

  • 当点击子对象时,则重新设置子对象的位置,使其右侧居中,并且向 X 轴的正半轴偏移 100 像素,此时,子对象超出父对象的部分默认不可见。

马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/thin-wind/lvgl.git
git@gitee.com:thin-wind/lvgl.git
thin-wind
lvgl
LVGL
main

搜索帮助

246c6175 1850385 950819b3 1850385