LVGL:核心部件

一、组的概念

LVGL中"组"(Group)是一个用于管理用户界面元素集合的概念。它允许开发人员将多个对象组织在一起,并作为一个整体进行操作。

创建一个组的主要目的是为了实现事件分发和交互控制。通过将UI组件加入到同一个组中,可以:

  • 事件处理:当一个组中的某个对象接收到用户输入事件(如点击、触摸等)时,可以通过设置组的事件处理器来决定是立即处理该事件还是让其他组成员有机会响应此事件。
  • 焦点管理:在有键盘或编码器等输入设备的情况下,组可以管理哪些对象当前具有输入焦点,以便正确地切换焦点并更新用户界面状态。
  • 整体控制:通过对组的操作,可以同时对一组对象进行隐藏、显示、移除、添加样式等操作,方便了用户界面状态的整体管理。

要创建并使用一个组,通常会调用 lv_group_t *lv_group_create(void) 创建一个组对象,然后调用 lv_obj_add_to_group(obj, group) 将对象添加到指定的组中。

1.1、默认组

LVGL提供了一个默认的输入设备组,这个组通常用于处理按键、触摸屏等输入事件。开发者可以通过调用 lv_group_t *lv_group_get_default(void) 函数来获取默认的组对象,并将UI组件添加到该组中,这样这些组件就可以响应键盘或触摸等输入事件。

可以使用 lv_group_set_default(lv_group_t *group) 函数来指定一个自定义组作为新的默认组。这样,新创建的对象如果没有显式地加入其他组,就会自动加入到默认组中。

二、核心部件

2.1、按钮 lv_btn

用法与基础对象的用法一致。默认情况下,按钮在以下方面与基础对象不同:

  • 不可滚动
  • 添加到默认组
  • 默认高度和宽度设置为 LV_SIZE_CONTENT(自动调整)

2.1.1、设置check状态

static void event_handler(lv_event_t * e)
{
    lv_obj_t *btn = lv_event_get_target(e);
    lv_event_code_t code = lv_event_get_code(e);

    if(code == LV_EVENT_VALUE_CHANGED)
    {
        lv_state_t state = lv_obj_get_state(btn);
        if(state & LV_STATE_CHECKED)
        {
            LV_LOG_USER("is checked");
        }
        else
        {
            LV_LOG_USER("is unchecked");
        }
    }
}

void esp32_log_cb(const char * buf)
{
    std::cout<<buf<<std::endl;
}

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);//注册日志输出回调函数

    {
        lv_obj_t * label;

        lv_obj_t * btn1 = lv_btn_create(lv_scr_act());
        lv_obj_add_event_cb(btn1, event_handler, LV_EVENT_ALL, NULL);
        lv_obj_add_flag(btn1,LV_OBJ_FLAG_CHECKABLE);
        lv_obj_center(btn1);

        label = lv_label_create(btn1);
        lv_label_set_text(label, "Button");
        lv_obj_center(label);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

2.2.2、包含组件元素

  • LV_PART_MAIN:组件的主要背景部分,通常是一个类似矩形的区域。

2.2.3、使用例子

这两个例子都是来自百问网,这里只是增加了注释和一些修改。

例1:

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);//注册日志输出回调函数

    {
        static lv_style_t style_defaultState;
        {
            lv_style_init(&style_defaultState);

            //背景
            lv_style_set_bg_opa(&style_defaultState, LV_OPA_100);//设置背景不透明度为完全不透明(LV_OPA_100)
            lv_style_set_bg_color(&style_defaultState, lv_palette_main(LV_PALETTE_BLUE));//设置背景颜色为主色调中的蓝色
            lv_style_set_bg_grad_color(&style_defaultState, lv_palette_main(LV_PALETTE_RED));//设置渐变背景色为红色
            // lv_style_set_bg_grad_color(&style, lv_palette_darken(LV_PALETTE_BLUE, 10));//设置渐变背景颜色为深2级的蓝色
            lv_style_set_bg_grad_dir(&style_defaultState, LV_GRAD_DIR_VER);// 设置背景渐变方向为垂直方向

            //边框
            lv_style_set_border_opa(&style_defaultState, LV_OPA_40);//设置边框不透明度为40%
            lv_style_set_border_width(&style_defaultState, 2);//设置边框宽度为2像素
            lv_style_set_border_color(&style_defaultState, lv_color_hex(0x128bf1));// 设置边框颜色

            //阴影
            lv_style_set_shadow_width(&style_defaultState, 8);// 设置阴影宽度为8像素
            lv_style_set_shadow_opa(&style_defaultState,LV_OPA_50);//设置阴影不透明度
            lv_style_set_shadow_color(&style_defaultState, lv_palette_main(LV_PALETTE_GREEN));//设置阴影颜色
            lv_style_set_shadow_ofs_y(&style_defaultState, 8);// 设置阴影在Y轴上的偏移量为8像素

            //外轮廓
            lv_style_set_outline_opa(&style_defaultState, LV_OPA_70);//设置外轮廓不透明度
            lv_style_set_outline_color(&style_defaultState, lv_palette_main(LV_PALETTE_LIGHT_BLUE));//设置外轮廓颜色

            //其他
            lv_style_set_radius(&style_defaultState, 3);//设置圆角半径为3像素
            lv_style_set_text_color(&style_defaultState, lv_color_white());//设置文本颜色为白色
            lv_style_set_pad_all(&style_defaultState, 10);//设置内填充间距为10像素(上下左右各10像素)
        }

        static lv_style_t style_pressState;
        {
            lv_style_init(&style_pressState);

            //外轮廓
            lv_style_set_outline_width(&style_pressState, 30);//外轮廓宽度
            lv_style_set_outline_opa(&style_pressState, LV_OPA_TRANSP);//设置外轮廓不透明度

            //背景
            lv_style_set_bg_color(&style_pressState, lv_palette_darken(LV_PALETTE_BLUE, 2));
            lv_style_set_bg_grad_color(&style_pressState, lv_palette_darken(LV_PALETTE_BLUE, 4));

            //其他
            lv_style_set_translate_y(&style_pressState, 5);//控件垂直位移5像素
            lv_style_set_shadow_ofs_y(&style_pressState, 3);//阴影在Y轴方向上的偏移量
        }

        //过渡动画
        static lv_style_prop_t props[] = {LV_STYLE_OUTLINE_WIDTH,   //宽度变化
                                          LV_STYLE_OUTLINE_OPA,     //透明度变化
                                          LV_STYLE_PROP_INV};       //结束符号
        static lv_style_transition_dsc_t outline_transition_dsc;
        lv_style_transition_dsc_init(&outline_transition_dsc, props, lv_anim_path_linear, 300, 0, NULL);

        //设置按下状态样式的过渡效果
        lv_style_set_transition(&style_pressState, &outline_transition_dsc);

        lv_obj_t * btn = lv_btn_create(lv_scr_act());
        lv_obj_remove_style_all(btn);//移除来自主题的默认样式
        lv_obj_add_style(btn, &style_defaultState, 0);//设置按钮默认样式
        lv_obj_add_style(btn, &style_pressState, LV_STATE_PRESSED);//设置按钮按下样式
        lv_obj_set_size(btn, LV_SIZE_CONTENT, LV_SIZE_CONTENT);// 设置按钮尺寸适应内容大小
        lv_obj_center(btn);

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

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

例2:

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);//注册日志输出回调函数

    {
        //过渡中使用动画的属性
        static lv_style_prop_t props[] =
        {
            LV_STYLE_TRANSFORM_WIDTH,   // 宽度
            LV_STYLE_TRANSFORM_HEIGHT,  // 高度
            LV_STYLE_TEXT_LETTER_SPACE, // 文本字符之间的间距
            LV_STYLE_PROP_INV           // 标志符,表示数组结束
        };

        // 创建并初始化默认状态下按钮的样式,并设置其动画过渡效果为 transition_dsc_def
        static lv_style_t style_def;
        {
            //从按下状态到默认状态的动画
            static lv_style_transition_dsc_t transition_dsc_to_def;
            lv_style_transition_dsc_init(&transition_dsc_to_def,
                                         props,
                                         lv_anim_path_overshoot,
                                         250 /* 动画时长 */,
                                         100 /* 延迟时间,添加了延迟,确保即使按下时间很短也能看到按下的过渡效果 */,
                                         NULL);

            lv_style_init(&style_def);
            lv_style_set_transition(&style_def, &transition_dsc_to_def);
        }

        //按下状态下按钮的样式
        static lv_style_t style_pressState;
        {
            //从默认状态到按下状态的动画
            static lv_style_transition_dsc_t transition_dsc_to_press;
            lv_style_transition_dsc_init(&transition_dsc_to_press,
                                         props,
                                         lv_anim_path_ease_in_out,
                                         1000 /* 动画时长 */,
                                         0 /* 没有延迟,立即进行按下 */,
                                         NULL);

            lv_style_init(&style_pressState);
            lv_style_set_transform_width(&style_pressState, 10);    //按下时宽度增加10单位
            lv_style_set_transform_height(&style_pressState, -6);   //按下时高度减小6单位
            lv_style_set_text_letter_space(&style_pressState, 10);  //按下时文本字符间距增大10单位
            lv_style_set_transition(&style_pressState, &transition_dsc_to_press);
        }

        lv_obj_t * btn = lv_btn_create(lv_scr_act());
        lv_obj_center(btn);
        lv_obj_t * label = lv_label_create(btn);
        lv_label_set_text(label, "Gum");
        lv_obj_center(label);

        lv_obj_add_style(btn, &style_def, LV_STATE_DEFAULT);
        lv_obj_add_style(btn, &style_pressState, LV_STATE_PRESSED);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

2.2、开关 lv_switch

2.2.1、包含组件元素

  • LV_PART_MAIN:组件的主要背景部分,通常是一个类似矩形的区域。
  • LV_PART_INDICATOR:指示器部分,开关的勾选框。
  • LV_PART_KNOB:旋钮或手柄部分,用户可以通过它来调整数值或位置。

2.2.2、事件处理

static void event_handler(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);

    if(code == LV_EVENT_VALUE_CHANGED)
    {
        lv_obj_t *obj = lv_event_get_target(e);
        if(lv_obj_has_state(obj, LV_STATE_CHECKED))
        {
            LV_LOG_USER("is checked");
        }
        else
        {
            LV_LOG_USER("is unchecked");
        }
    }
}

void esp32_log_cb(const char * buf)
{
    std::cout<<buf<<std::endl;
}

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);//注册日志输出回调函数

    {
        lv_obj_t *toggle = lv_switch_create(lv_scr_act());
        lv_obj_add_event_cb(toggle, event_handler, LV_EVENT_ALL, NULL);
        lv_obj_center(toggle); // 将开关居中显示
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

2.3、复选框 lv_checkbox

2.3.1、包含组件元素

  • LV_PART_MAIN:组件的主要背景部分,通常是一个类似矩形的区域。pad_column 属性调整复选框和标签之间的间距
  • LV_PART_INDICATOR:指示器部分,开关的勾选框。padding 属性使复选框在相应方向上变大。

2.3.2、事件处理

处理 LV_EVENT_VALUE_CHANGED 事件的方式和 lv_switch 一样。

2.3.3、使用例子

此例子来自于百问网。把复选框当做单选按钮处理:

void esp32_log_cb(const char * buf)
{
    std::cout<<buf<<std::endl;
}

static uint32_t active_index_1 = 0;
static uint32_t active_index_2 = 0;

static void radio_event_handler(lv_event_t * e) // 单选按钮事件处理程序
{
    lv_obj_t * cont = lv_event_get_current_target(e);       // 获取事件的当前目标对象
    lv_obj_t * act_cb = lv_event_get_target(e);             // 获取事件的目标对象

    if(act_cb == cont)
    {
        return;
    }

    auto active_id = (int32_t*)lv_event_get_user_data(e);   // 获取用户数据,并将其转换为int32_t类型
    lv_obj_t * old_cb = lv_obj_get_child(cont,
                                        *active_id);        // 获取容器中当前激活单选按钮的对象

    lv_obj_clear_state(old_cb, LV_STATE_CHECKED);           //取消选中前一个单选按钮
    lv_obj_add_state(act_cb, LV_STATE_CHECKED);             //选中当前单选按钮

    *active_id = lv_obj_get_index(act_cb); // 更新激活单选按钮的索引

    LV_LOG_USER("Selected radio buttons: %d, %d", (int)active_index_1, (int)active_index_2); // 输出当前选择的单选按钮的索引
}

int main(int argc, char **argv)
{
    lv_init(); // 初始化LVGL库
    hal_init(); // 初始化硬件抽象层(HAL)

    lv_log_register_print_cb(esp32_log_cb); // 注册日志输出回调函数

    {
        static lv_style_t style_radio;
        lv_style_init(&style_radio);
        lv_style_set_radius(&style_radio, LV_RADIUS_CIRCLE); // 设置样式的圆角半径为圆形

        static lv_style_t style_radio_chk;
        lv_style_init(&style_radio_chk);
        lv_style_set_bg_img_src(&style_radio_chk, NULL);    // 设置背景图像资源为空,也就是清除打钩符号

        lv_obj_t * cont1 = lv_obj_create(lv_scr_act());
        lv_obj_set_flex_flow(cont1, LV_FLEX_FLOW_COLUMN);   // 设置对象的布局为列布局
        lv_obj_set_size(cont1, lv_pct(40), lv_pct(80));     // 设置对象的大小为相对于父容器的百分比
        lv_obj_add_event_cb(cont1,
                            radio_event_handler,
                            LV_EVENT_CLICKED,
                            &active_index_1); // 添加点击事件回调函数,并传递active_index_1作为用户数据

        for (auto i = 0;i < 5;i++)
        {
            char buf[32];
            lv_snprintf(buf, sizeof(buf), "A %d", i + 1); // 格式化生成文本

            lv_obj_t * obj = lv_checkbox_create(cont1);
            lv_checkbox_set_text(obj, buf);                             // 设置复选框的文本
            lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE);             // 将事件传递给父对象
            lv_obj_add_style(obj, &style_radio, LV_PART_INDICATOR);     // 添加样式到复选框对象的指示器部分
            lv_obj_add_style(obj, &style_radio_chk, LV_PART_INDICATOR | LV_STATE_CHECKED); // 添加样式到复选框对象的指示器部分,并设置为选中状态
        }

        lv_obj_add_state(lv_obj_get_child(cont1, 0), LV_STATE_CHECKED); // 设置容器中的第一个子对象为选中状态

        lv_obj_t * cont2 = lv_obj_create(lv_scr_act());
        lv_obj_set_flex_flow(cont2, LV_FLEX_FLOW_COLUMN);
        lv_obj_set_size(cont2, lv_pct(40), lv_pct(80));
        lv_obj_set_x(cont2, lv_pct(50)); // 设置对象的x坐标为相对于父容器的百分比
        lv_obj_add_event_cb(cont2,
                            radio_event_handler,
                            LV_EVENT_CLICKED,
                            &active_index_2); // 添加事件回调函数到对象的点击事件,并传递active_index_2作为用户数据

        for (auto i = 0;i < 3;i++)
        {
            char buf[32];
            lv_snprintf(buf, sizeof(buf), "B %d", (int)i + 1); // 格式化生成文本

            lv_obj_t * obj = lv_checkbox_create(cont2);
            lv_checkbox_set_text(obj, buf);
            lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE);
            lv_obj_add_style(obj, &style_radio, LV_PART_INDICATOR);
            lv_obj_add_style(obj, &style_radio_chk, LV_PART_INDICATOR | LV_STATE_CHECKED);
        }
        lv_obj_add_state(lv_obj_get_child(cont2, 0), LV_STATE_CHECKED); // 设置容器中的第一个子对象为选中状态
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000); // 程序延时5毫秒
    }

    return 0;
}

2.3.4、相关函数

1、void lv_checkbox_set_text(lv_obj_t *obj, const char *txt)

设置指定复选框对象的文本内容。会将传入的字符串 `txt` 内容复制到复选框中,因此在函数调用返回后,原始的 `txt` 字符串可以被释放或修改。

参数2如果传入 `NULL`,则复选框会刷新并显示当前已存在的文本(如果有)。

2、void lv_checkbox_set_text_static(lv_obj_t *obj, const char *txt)`

设置指定复选框对象的文本内容。这里的 `txt` 字符串必须在整个复选框生命周期内有效,即不能在设置之后进行释放或更改。

3、const char *lv_checkbox_get_text(const lv_obj_t *obj)

获取指定复选框对象的当前文本内容。

2.4、标签 lv_label

2.4.1、包含组件元素

  • LV_PART_MAIN: 组件的主要区域,包括背景和文本。
  • LV_PART_SCROLLBAR: 当文本大于小部件的大小时显示的滚动条。
  • LV_PART_SELECTED: 该部分表示被选中文本的样式。只能使用 text_color(文本颜色)和 bg_color(背景颜色)这两个属性。

2.4.2、相关函数

1、void lv_label_set_text(lv_obj_t *obj, const char *text)

用法与2.3.4的同名的函数一致。

可以用\n换行:

        lv_obj_t * label = lv_label_create(lv_scr_act());
        lv_label_set_text(label,"line1\nline2\n\nline4");
        lv_obj_center(label);

2、void lv_label_set_text_static(lv_obj_t *obj, const char *text)

用法与2.3.4的同名的函数一致。

3、void lv_label_set_text_fmt(lv_obj_t * obj, const char * fmt, ...)

此函数提供了类似C语言 printf 函数的格式化功能来设置标签文本。可以使用占位符与变量相结合的方式来动态生成文本内容。

        lv_obj_t * label = lv_label_create(lv_scr_act());
        int current_temperature = 25;

        lv_label_set_text_fmt(label, "current temperature : %d℃", current_temperature);
        lv_obj_center(label);

4、void lv_label_set_long_mode(lv_obj_t *obj, lv_label_long_mode_t long_mode)

设置当标签的文本内容长度超过其对象尺寸时的行为方式。

在设置了模式之后,应当在调用此函数之后为标签对象重新设置尺寸,以确保正确实现相应的长文本处理效果。

  • LV_LABEL_LONG_WRAP:当文本过长时,保持对象宽度不变,将过长的行进行自动换行,并根据需要扩展对象的高度以适应所有文本内容。
  • LV_LABEL_LONG_DOT:保持标签的原始尺寸不变,如果文本太长,则在末尾添加省略号(...),表示文本被截断。
  • LV_LABEL_LONG_SCROLL:保持标签大小固定,当文本超出时,使其内容从右至左或从下至上滚动显示。
  • LV_LABEL_LONG_SCROLL_CIRCULAR:类似于滚动模式,但到达一端后会循环回到另一端继续滚动,实现循环滚动效果。
  • LV_LABEL_LONG_CLIP:保持标签的尺寸不变,对于超出部分的文本直接裁剪掉,即只显示能完全容纳在标签尺寸内的文本内容。

对于 LV_LABEL_LONG_DOT 模式,会直接在原地修改文本缓冲区以添加或移除省略号。即如果使用 lv_label_set_text lv_label_set_array_text 函数来动态分配并设置文本内容,会自动创建一个新的缓冲区,并在这个新缓冲区上执行省略号相关的操作。

然而,在使用 lv_label_set_text_static 函数时情况有所不同。此函数要求用户传入一个静态文本缓冲区指针,该缓冲区在整个标签对象生命周期内有效且不可更改。如果计划在使用 LV_LABEL_LONG_DOT 模式的同时使用 lv_label_set_text_static 设置文本内容,则传入的缓冲区必须是可写的,因为需要能够直接在该缓冲区内添加或删除省略号以适应长文本显示的需求。如果不满足这一条件,可能导致程序行为异常或者数据损坏。

5、void lv_label_set_recolor(lv_obj_t *label, bool en)

在文本字符串中插入特定格式的代码来定义颜色更改。参数2启用或禁用文本重新着色功能。

颜色和文本用 #包住:#颜色1 文本1# , #颜色2 文本2# , #颜色3 文本3#

        lv_obj_t *label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "#FF0000 Red# #00FF00 Green# #0000FF Blue text#");
        lv_label_set_recolor(label, true);
        lv_obj_center(label);

6、void lv_label_set_text_sel_start(lv_obj_t *obj, uint32_t index)

      void lv_label_set_text_sel_end(lv_obj_t *obj, uint32_t index)  

设置文本选择开始 / 结束的位置。

从0开始计数的字符索引,表示选中应该从哪个字符开始。如果传入 LV_LABEL_TEXT_SELECTION_OFF 常量,则取消所有文本选择。

        lv_obj_t *label = lv_label_create(lv_scr_act());
        lv_obj_add_flag(label,LV_OBJ_FLAG_CLICKABLE);
        lv_label_set_text(label, "Hello, World!");
        lv_label_set_text_sel_start(label, 7); // 从第8个字符('W')开始选择文本
        lv_label_set_text_sel_end(label, 12); // 结束选择在第13个字符('!')之前
        lv_obj_center(label);

7、void lv_label_get_letter_pos(const lv_obj_t *obj, uint32_t char_id, lv_point_t *pos)

根据给定的字符索引,计算出该字符在标签内部的x和y坐标,并将结果存储在一个指向 lv_point_t 结构体的指针所指向的位置。

        lv_obj_t *label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "Hello, World!");
        lv_obj_center(label);

        lv_point_t letter_pos;
        lv_label_get_letter_pos(label, 7, &letter_pos); // 获取"World!"中的"W"字符位置
        printf("The position of character at index 7 is (%d, %d)\n", letter_pos.x, letter_pos.y);

8、uint32_t lv_label_get_letter_on(const lv_obj_t *obj, lv_point_t *pos_in);

获取标签上指定相对位置点的字符的索引。

获取像素位置(100,0)这个点的字符是label上文本的索引:

        lv_obj_t *label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "Hello, World!");
        lv_obj_center(label);

        lv_point_t pos;
        pos.x = 100; // 假设这里的x坐标对应到某个字符的位置
        pos.y = 0;
        uint32_t letter_index = lv_label_get_letter_on(label, &pos);
        printf("The index of the character at position (%d, %d) is: %d\n", pos.x, pos.y, letter_index);

9、bool lv_label_is_char_under_pos(const lv_obj_t *obj, lv_point_t *pos)

检测某个点下方是否绘制有字符的函数。

        lv_obj_t *label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "Hello, World!");
        lv_obj_center(label);

        lv_point_t pos;
        pos.x = 100; // 假设这里的x坐标对应到某个字符的位置
        pos.y = 0;

        bool is_char_under = lv_label_is_char_under_pos(label, &pos);

        if(is_char_under)
        {
            printf("There is a character under the point (%d, %d)\n", pos.x, pos.y);
        }
        else
        {
            printf("There is no character under the point (%d, %d)\n", pos.x, pos.y);
        }

10、void lv_label_ins_text(lv_obj_t *obj, uint32_t pos, const char *txt);

向标签对象的指定字符位置插入文本的函数。适用于动态分配内存的标签,不适用于静态文本。

参数2是插入文本的位置,以字符索引表示(而不是字节索引)。如果为 0,则文本将被插入到现有文本的第一个字符之前;如果等于 LV_LABEL_POS_LAST,则文本将在最后一个字符之后追加。

        lv_obj_t *label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "Hello, ");
        lv_obj_center(label);

        uint32_t insert_pos = 6;
        const char *inserted_text = "World!";

        lv_label_ins_text(label, insert_pos, inserted_text);

11、void lv_label_cut_text(lv_obj_t *obj, uint32_t pos, uint32_t cnt);

从标签对象的指定位置开始删除一定数量字符的函数。该函数适用于动态分配内存的标签,不适用于静态文本。

参数3是要删除的字符数量。

        lv_obj_t *label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "Hello, World!");
        lv_obj_center(label);        

        // 从第7个字符开始删除5个字符
        uint32_t cut_start_pos = 6; // 第7个字符的索引
        uint32_t chars_to_cut = 5;
        lv_label_cut_text(label, cut_start_pos, chars_to_cut);

2.5、图像 lv_img

2.5.1、包含组件元素

  • LV_PART_MAIN: 组件的主要区域。

2.5.2、相关函数

1、void lv_img_set_src(lv_obj_t *obj, const void *src)

设置图像对象显示内容。

参数2是指向图像数据源的指针。它可以是以下三种类型:

  • 指向已由LVGL图像转换器转换过的图像描述符(lv_img_dsc_t)的指针。例如,如果使用了 LVGL 的在线或本地图像转换工具将图片转换为二进制格式,并得到了一个结构体变量,那么可以直接传入该结构体的地址。
  • 图像文件的路径字符串。该路径可以是相对路径或者绝对路径,指向存储在LittlevGL支持的文件系统中的图像文件。通常文件应是LVGL能识别的二进制格式。
  • LVGL 内置的符号(SYMBOL)。LVGL提供了一些预定义的图形符号,可以直接用作图像资源。
  • 标签作为图像:

    这样的图像不能旋转、缩放。

2、void lv_img_set_offset_x(lv_obj_t *obj, lv_coord_t x)

      void lv_img_set_offset_y(lv_obj_t *obj, lv_coord_t y)

设置图像源的X轴 / Y轴偏移量。

3、void lv_img_set_angle(lv_obj_t *obj, int16_t angle)

设置图像对象的旋转角度。旋转角度单位是0.1度(0-3600,其中3600相当于360度)。例如,返回值为900表示图像顺时针旋转了90度。

     void lv_img_set_pivot(lv_obj_t *obj, lv_coord_t x, lv_coord_t y)

设置图像对象的旋转中心。

4、void lv_img_set_zoom(lv_obj_t *obj, uint16_t zoom)

设置图像对象的缩放级别。

参数2指定缩放因子:

  • 当 zoom 值为100时,图像将以其原始大小显示
  • 当 zoom 值大于100时,图像会被放大
  • 当 zoom 值小于100时,则会缩小显示

例如,如果 zoom 设置为200,则图像将被放大一倍;若设置为50,则图像尺寸会减半。

5、void lv_img_set_antialias(lv_obj_t *obj, bool antialias)

控制图像对象在进行变换(如旋转、缩放)时是否启用抗锯齿功能。

当启用抗锯齿时,这样可以使得图像边缘更加平滑,视觉效果更好,但可能会增加图形渲染的计算复杂性和时间开销,从而影响性能。

6、void lv_img_set_size_mode(lv_obj_t *obj, lv_img_size_mode_t mode);

设置图像对象尺寸模式的函数。尺寸模式决定了图像如何适应其父容器的尺寸或者其自身的尺寸。

  • LV_IMG_SIZE_MODE_VIRTUAL:当设置此模式时,缩放不会影响图像对象的实际坐标位置。如果放大图像,超出对象坐标范围的部分仍然会被绘制出来,但是布局不会因为缩放而改变。
  • LV_IMG_SIZE_MODE_REAL:当对象大小设置为 SIZE_CONTENT 时,对象的大小将会等于缩放后的图像大小,即着图像的缩放会导致布局的重新计算。如果对象的大小是明确设置的(非 SIZE_CONTENT),那么当图像被放大以至于超过对象大小时,图像会被裁剪以适应对象大小。

2.5.3、其他

1、颜色混合

        lv_obj_t * img = lv_img_create(lv_scr_act());
        lv_img_set_src(img,"M:huaji.png");
        lv_obj_center(img);

        static lv_style_t style;
        lv_style_init(&style);
        lv_style_set_img_recolor(&style, LV_COLOR_MAKE(0xA0, 0xB0, 0xFF));// 浅蓝色
        lv_style_set_img_recolor_opa(&style, LV_OPA_50);
        lv_obj_add_style(img, &style, LV_PART_MAIN);

2、图像填充

当图像对象的尺寸大于其所装载图像的实际尺寸时,图像将会像马赛克一样在必要的方向上重复填充,以便填满整个图像对象区域。这一特性允许开发者仅使用一个很小的源图像,通过重复铺贴来生成一个大的背景或图案。

        lv_obj_t * img = lv_img_create(lv_scr_act());
        lv_img_set_src(img,"M:huaji.png");
        lv_obj_set_size(img, LV_HOR_RES, LV_VER_RES); // 设置为屏幕宽度和高度

2.6、下拉框 lv_dropdown

2.6.1、包含组件元素

按钮部分:

  • LV_PART_MAIN:背景。对其上的文本使用典型的背景属性和文本属性。
  • LV_PART_INDICATOR:默认是一个箭头符号,可以是图像或文本(LV_SYMBOL)。

列表部分:

  • LV_PART_MAIN:列表本身。使用典型的背景属性。max_height 可用于限制列表的高度。
  • LV_PART_SCROLLBAR:滚动条背景、边框、阴影属性和宽度以及右侧间距的右侧填充。
  • LV_PART_SELECTED:当前选择的选项或区域,如列表项的高亮显示。

由于下拉列表关闭时列表不存在,所以要某一事件触发后列表创建之后才能设置:

lv_style_t dropdown_list_style;

void on_dropdown_value_changed(lv_event_t* event)
{
    lv_event_code_t code = lv_event_get_code(event);

    if(code == LV_EVENT_CLICKED)
    {
        if( lv_obj_t * obj = lv_event_get_current_target(event))
        {
            if(lv_obj_t *list = lv_dropdown_get_list(obj))// 获取下拉列表的列表部分
            {
                lv_obj_add_style(list, &dropdown_list_style, LV_PART_MAIN);
            }
        }
    }
}

int main(int argc, char **argv)
{
    lv_init(); // 初始化LVGL库
    hal_init(); // 初始化硬件抽象层(HAL)

    lv_log_register_print_cb(esp32_log_cb); // 注册日志输出回调函数
    lv_style_init(&dropdown_list_style);
    lv_style_set_bg_color(&dropdown_list_style, lv_color_hex(0x0000FF));

    {
        lv_obj_t *dropdown = lv_dropdown_create(lv_scr_act());
        lv_dropdown_set_options(dropdown, "Option 1\nOption 2\nOption 3\nOption 4");
        lv_obj_add_event_cb(dropdown, on_dropdown_value_changed, LV_EVENT_CLICKED, NULL);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000); // 程序延时5毫秒
    }

    return 0;
}

2.6.2、相关函数

1、void lv_dropdown_set_text(lv_obj_t *obj, const char *txt);

设置下拉列表按钮文本的函数。如果参数2设置为一个具体的非空字符串,那么即使是切换选项,按钮上都将始终显示这个指定的文本字符串。

     void lv_dropdown_set_options(lv_obj_t *obj, const char *options)

设置下拉列表对象的选项,选项以换行符 \n 分隔的字符串形式给出。

例如:"One\nTwo\nThree" 将创建三个选项:"One"、"Two" 和 "Three"。

会复制并保存 options 到对象中,因此在调用此函数后,原始选项字符串可以被释放或修改。

     void lv_dropdown_set_options_static(lv_obj_t *obj, const char *options)

类似于上面的 lv_dropdown_set_options,但它接受静态字符串作为参数。即传入的字符串必须是全局变量、静态变量或动态分配的内存空间,并且在设置之后不应被修改或释放。

下拉列表对象只保存选项字符串的指针,而不复制选项内容。

     void lv_dropdown_add_option(lv_obj_t *obj, const char *option, uint32_t pos)

向下拉列表对象中添加一个新的选项。选项以字符串形式给出,不包含换行符。

例如:"Four" 将添加一个名为 "Four" 的新选项。

pos 参数指定了插入位置,从0开始索引,如果设置为 LV_DROPDOWN_POS_LAST,则表示在现有选项的最后添加。

     void lv_dropdown_clear_options(lv_obj_t *obj)

清除下拉列表中的所有选项,无论是静态分配还是动态分配的选项都会被移除。

2、void lv_dropdown_set_selected(lv_obj_t *obj, uint16_t sel_opt)

设置下拉列表中被选中的选项。参数2是要选中的选项编号。选项编号从0开始计数。

如果提供的选项编号超出了实际选项数量的范围,行为未明确定义,可能不会有任何效果或导致不可预期的行为。

3、void lv_dropdown_set_dir(lv_obj_t *obj, lv_dir_t dir)

设置下拉列表弹出方向。

默认情况下,下拉列表通常会根据其在屏幕上的位置自动选择一个合适的展开方向,但通过调用此函数,可以强制指定一个固定的方向。

  • LV_DIR_LEFT:左
  • LV_DIR_RIGHT:右
  • LV_DIR_TOP:上
  • LV_DIR_BOTTOM:下
        lv_obj_t *parent_screen = lv_disp_get_scr_act(NULL); // 获取当前活动屏幕
        lv_dir_t dirs[] = {LV_DIR_BOTTOM,
                           LV_DIR_TOP,
                           LV_DIR_LEFT,
                           LV_DIR_RIGHT};

        for (int i = 0; i < 4; i++)
        {
            lv_obj_t * obj  = lv_dropdown_create(parent_screen);
            lv_obj_set_size(obj, 100, 50);
            lv_obj_align(obj, LV_ALIGN_LEFT_MID, i * 120 + 50, 0); // 水平排列,间距120
            lv_dropdown_set_options(obj, "Option 1\nOption 2\nOption 3");
            lv_dropdown_set_dir(obj, dirs[i]);
        }

4、void lv_dropdown_set_symbol(lv_obj_t *obj, const void *symbol);

设置下拉列表按钮上的符号。

参数2指定要显示的符号的指针或者路径。它可以是以下几种类型:

  • 预定义文本标识
  • 图像资源
  • NULL:如果传递 NULL,则不会在下拉列表按钮上绘制任何符号图标。
        lv_obj_t * dropdown = lv_dropdown_create(lv_scr_act());
        lv_obj_align(dropdown, LV_ALIGN_TOP_LEFT, 10, 10);
        lv_dropdown_set_options(dropdown, "New project\n"
                                          "New file\n"
                                          "Save\n"
                                          "Save as ...\n"
                                          "Open project\n"
                                          "Recent projects\n"
                                          "Preferences\n"
                                          "Exit");

        lv_dropdown_set_text(dropdown, "Menu");
        lv_dropdown_set_symbol(dropdown, LV_SYMBOL_AUDIO);
        lv_obj_set_style_transform_angle(dropdown, 1800, LV_PART_INDICATOR | LV_STATE_CHECKED);
        lv_dropdown_set_selected_highlight(dropdown, false);

5、void lv_dropdown_set_selected_highlight(lv_obj_t *obj, bool en)

控制下拉列表中的选项是否高亮显示选中项。默认是开启高亮显示的。

6、lv_obj_t *lv_dropdown_get_list(lv_obj_t *obj)

获取组件内列表部分对象的指针。

7、uint16_t lv_dropdown_get_option_cnt(const lv_obj_t *obj)

获取下拉列表对象中选项的总数。

8、void lv_dropdown_get_selected_str(const lv_obj_t *obj, char *buf, uint32_t buf_size)

获取下拉列表当前选中的选项,并将其内容以字符串形式存放在指定的缓冲区buf中。

buf_size 表示缓冲区buf的大小(以字节为单位)。如果设置为0,则函数会忽略缓冲区大小限制,但务必确保缓冲区足够大以容纳选中选项的字符串,否则可能会导致溢出。

static void event_cb(lv_event_t * e)
{
    lv_obj_t * dropdown = lv_event_get_target(e);
    char buf[64];
    lv_dropdown_get_selected_str(dropdown, buf, sizeof(buf));
    LV_LOG_USER("'%s' is selected", buf);
}

9、void lv_dropdown_open(lv_obj_t *obj)

      void lv_dropdown_close(lv_obj_t *obj)

打开 / 关闭的下拉框的列表组件。

2.7、进度条 lv_bar

2.7.1、包含组件元素

  • LV_PART_MAIN:进度条的背景。
  • LV_PART_INDICATOR:指示器部分。

2.7.2、相关函数

1、void lv_bar_set_value(lv_obj_t *obj, int32_t value, lv_anim_enable_t anim)

设置进度条对象的新值。这个数值必须位于最小值和最大值之间。

参数3决定是否采用动画效果来更新数值。

  • LV_ANIM_ON:进度条的值将以动画的形式逐渐过渡到新值
  • LV_ANIM_OFF:立即切换到新值

2、void lv_bar_set_start_value(lv_obj_t *obj, int32_t start_value, lv_anim_enable_t anim)

设置进度条对象的起始值。通常,起始值是进度条从左端开始计算的基准点,即刻度0对应的位置。

3、void lv_bar_set_range(lv_obj_t *obj, int32_t min, int32_t max)

设置进度条对象的最小值和最大值。这两个值界定了进度条的整个工作区间,进度条的值必须在这个范围内变动。

4、 void lv_bar_set_mode(lv_obj_t *obj, lv_bar_mode_t mode)

设置进度条对象的模式。

  • LV_BAR_MODE_NORMAL:普通模式,进度条从左侧开始填充至右侧,根据设置的值显示进度。
  • LV_BAR_MODE_SYMMETRICAL:对称模式,进度条从中心点向两侧填充。例如当值为0时,进度条在中间,正负值分别向两边扩展。
  • LV_BAR_MODE_RANGE:范围模式,进度条可以展示两个值之间的范围,比如用作双滑块或范围选择器,可能会有两个可移动的指示器。

2.7.3、一些例子

例子来着百问网

例1:

//用于设置进度条的值
static void set_temp(void *bar, int32_t temp)
{
    lv_bar_set_value((lv_obj_t *)bar, temp, LV_ANIM_ON);
}

int main(int argc, char **argv)
{
    lv_init();

    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        //指示器部分的样式
        static lv_style_t style_indic;
        lv_style_init(&style_indic);
        lv_style_set_bg_opa(&style_indic, LV_OPA_COVER);// 设置指示器部分的背景不透明度为完全不透明

        //背景颜色和渐变颜色
        lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_RED)); // 主红色
        lv_style_set_bg_grad_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE)); // 主蓝色
        lv_style_set_bg_grad_dir(&style_indic, LV_GRAD_DIR_VER);// 设置背景渐变方向为垂直方向

        lv_obj_t *bar = lv_bar_create(lv_scr_act());
        lv_obj_set_size(bar, 20, 200);
        lv_bar_set_range(bar, -20, 40);
        lv_obj_center(bar);
        lv_obj_add_style(bar, &style_indic, LV_PART_INDICATOR);//样式应用到进度条的指示器部分

        //动画结构体
        lv_anim_t a;
        lv_anim_init(&a);
        lv_anim_set_exec_cb(&a, set_temp);// 设置动画执行时调用的回调函数为set_temp
        lv_anim_set_time(&a, 3000);// 设置动画完成一次完整变化所需的时间为3秒
        lv_anim_set_playback_time(&a, 3000);// 设置动画回放时间也为3秒,即动画会来回循环播放
        lv_anim_set_var(&a, bar);// 设置动画的目标变量为进度条对象
        lv_anim_set_values(&a, -20, 40);// 设置动画开始和结束的值,即从-20过渡到40
        lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);// 设置动画重复次数为无限次,使动画循环播放
        lv_anim_start(&a);// 启动动画
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

例2:

        lv_obj_t * bar_ltr = lv_bar_create(lv_scr_act());
        lv_obj_set_size(bar_ltr, 200, 20);
        lv_bar_set_value(bar_ltr, 70, LV_ANIM_OFF);
        lv_obj_align(bar_ltr, LV_ALIGN_CENTER, 0, -30);

        lv_obj_t * label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "Left to Right base direction");
        lv_obj_align_to(label, bar_ltr, LV_ALIGN_OUT_TOP_MID, 0, -5);

        lv_obj_t * bar_rtl = lv_bar_create(lv_scr_act());
        lv_obj_set_style_base_dir(bar_rtl, LV_BASE_DIR_RTL, 0);
        lv_obj_set_size(bar_rtl, 200, 20);
        lv_bar_set_value(bar_rtl, 70, LV_ANIM_OFF);
        lv_obj_align(bar_rtl, LV_ALIGN_CENTER, 0, 30);

        label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "Right to Left base direction");
        lv_obj_align_to(label, bar_rtl, LV_ALIGN_OUT_TOP_MID, 0, -5);

 

2.8、弧形滑动条 lv_arc

搞清楚:弧度范围、表示的值的范围,其他和 lv_bar 大同小异。

2.8.1、包含组件元素

  • LV_PART_MAIN:背景。它使用典型的背景样式属性,例如颜色、不透明度、边框等。同时也会根据背景样式中的弧形属性绘制一个弧形(背景弧形。这个弧线的大小和位置会受到其内边距padding)样式属性的影响,即背景弧线与容器边缘之间的间距。
  • LV_PART_INDICATOR:这个部分用于绘制另一个弧形(指示器弧形,同样应用弧形样式属性。但指示器弧形的位置和大小会根据其与背景弧形的相对内边距来调整。
  • LV_PART_KNOB:这个部分在指示器弧形末端绘制一个手柄或旋钮。手柄的绘制会使用所有背景样式属性,包括但不限于颜色、图案、边框等。其内边距值用来确定手柄的大小。如果内边距为零,则手柄大小与指示器宽度相同;若内边距较大,则手柄会相应增大;若内边距较小,则手柄会变小。

2.8.2、相关函数

1、void lv_arc_set_start_angle(lv_obj_t *arc, uint16_t start);

设置指示器弧形组件的起始角度。

弧形的角度以顺时针方向为正,并且0度位于弧形的右中间位置(相当于钟表3点钟方向),然后依次是90度位于底部(6点钟方向)、180度位于左中间(9点钟方向)和270度位于顶部(12点钟方向)。

    void lv_arc_set_end_angle(lv_obj_t *arc, uint16_t end)

设置指示器弧形结束角度。

    void lv_arc_set_angles(lv_obj_t *arc, uint16_t start, uint16_t end)

设置指示器起始、结束角度。

2、void lv_arc_set_bg_start_angle(lv_obj_t *arc, uint16_t start)

     void lv_arc_set_bg_end_angle(lv_obj_t *arc, uint16_t end)

     void lv_arc_set_bg_angles(lv_obj_t *arc, uint16_t start, uint16_t end)

设置背景弧形起始、结束角度。

3、void lv_arc_set_rotation(lv_obj_t *arc, uint16_t rotation)

设置弧形对象的整体旋转角度。参数2为0表示不旋转,正数顺时针旋转,负数逆时针旋转。

4、void lv_arc_set_mode(lv_obj_t *arc, lv_arc_mode_t type)

设置模式,参数2见上面进度条的模式。

        lv_obj_t *scr = lv_scr_act();
        for(int i = LV_BAR_MODE_NORMAL;i <= LV_BAR_MODE_RANGE;++i)
        {
            lv_obj_t * obj = lv_arc_create(scr);
            lv_obj_set_size(obj,200,200);
            lv_obj_set_pos(obj,i*220 + 10,10);
            lv_arc_set_range(obj,-200,200);
            lv_arc_set_value(obj,50);
            lv_arc_set_mode(obj,i);
        }

5、void lv_arc_set_value(lv_obj_t *arc, int16_t value)

设置弧形组件显示值。此值通常用来控制弧形指示器的位置。根据弧形的最小值、最大值范围以及起始角度,新值会映射到弧形上的特定位置。

6、void lv_arc_set_change_rate(lv_obj_t *arc, uint16_t rate);

设置弧形组件在用户交互时其值变化速率。变化速率表示弧形达到被按下的点的速度限制。具体来说,它定义了每次LVGL任务循环时弧形指示器移动的最大单位值。数值越大,弧形响应用户的触摸或滑动动作时移动得越快;数值越小,则移动得越慢,甚至接近于平滑动画效果。

2.9、滑动条 lv_slider

2.9.1、包含组件元素

  • LV_PART_MAIN:进度条的背景。
  • LV_PART_INDICATOR:指示器部分。
  • LV_PART_KNOB:指示器末端绘制一个手柄或旋钮。

2.9.2、相关函数

1、bool lv_slider_is_dragged(const lv_obj_t *obj)

检测滑块是否正在被拖动。

其他函数用法和上面的进度条、弧形滑动条类似,略。

一个例子:

        lv_obj_t *scr = lv_scr_act();
        for(int i = LV_BAR_MODE_NORMAL;i <= LV_BAR_MODE_RANGE;++i)
        {
            lv_obj_t * obj = lv_slider_create(scr);
            lv_obj_set_size(obj,200,20);
            lv_obj_set_pos(obj,30,i*40 + 10);
            lv_slider_set_range(obj,-200,200);
            lv_slider_set_value(obj,50,LV_ANIM_OFF);
            lv_slider_set_mode(obj,i);
        }

2.10、滚动选择器 lv_roller

2.10.1、包含组件元素

  • LV_PART_MAIN
  1. 这个部分对应于滚动选择器的整体背景区域,包括其中未被选中的选项文本。
  2. 使用典型背景属性(如颜色、边框样式等)来定制滚动选择器背景的外观。
  3. 同时也使用文本样式属性(如字体、颜色、对齐方式等)来调整各个选项之间的间距(通过 style_text_line_space 属性设置)。
  4. 当滚动选择器滚动时,并非精确停在一个选项上时,它会在指定的时间(以毫秒为单位,通过 anim_time 样式属性设置)内自动滚动到最近的有效选项。
        lv_obj_t *roller = lv_roller_create(lv_scr_act());
        static lv_style_t style;
        lv_style_init(&style);
        lv_style_set_bg_color(&style, lv_color_hex(0xe8e8e8));
        lv_style_set_text_line_space(&style, 30); // 设置选项间距离为10像素
        lv_obj_add_style(roller, &style, LV_PART_MAIN);
        lv_roller_set_options(roller, "Option 1\nOption 2\nOption 3\nOption 4\nOption 5\nOption 6",LV_ROLLER_MODE_NORMAL);
        lv_obj_center(roller);

        lv_obj_set_style_anim_time(roller, 2000, LV_PART_MAIN); // 设置滚动到下一个选项所需时间为2000ms

  • LV_PART_SELECTED:滚动选择器中当前选中的那个选项的部分。
        lv_obj_t *roller = lv_roller_create(lv_scr_act());
        static lv_style_t selected_style;
        lv_style_init(&selected_style);
        lv_style_set_text_color(&selected_style, lv_color_hex(0xff0000)); // 设置选中文本为红色
        lv_obj_add_style(roller, &selected_style, LV_PART_SELECTED);
        lv_roller_set_options(roller, "Option 1\nOption 2\nOption 3\nOption 4\nOption 5\nOption 6",LV_ROLLER_MODE_NORMAL);
        lv_obj_center(roller);        

2.10.2、相关函数

1、void lv_roller_set_options(lv_obj_t *obj, const char *options, lv_roller_mode_t mode)

设置选项。参数3:

  • LV_ROLLER_MODE_NORMAL:滚动到末尾
  • LV_ROLLER_MODE_INFINITE:循环滚动

2、void lv_roller_set_visible_row_count(lv_obj_t *obj, uint8_t row_cnt)

设置滚动选择器显示的行数,即不滚动时显示的行数。此选项会改变控件的高度。

其他函数的用法与上面下拉框类似,略。

2.11、直线 lv_line

2.11.1、包含组件元素

  • LV_PART_MAIN:背景和线条样式。

2.11.2、相关函数

1、void lv_line_set_points(lv_obj_t *obj, const lv_point_t points[], uint16_t point_num)

设置线对象连接一系列的点。

参数2组包含了要在线上绘制的各个点。函数只保存了这个数组的地址,所以在整个线对象存在期间,需要确保这个数组也在内存中有效且不被修改。

参数3表示在绘制时使用的数组中点的个数。

2、void lv_line_set_y_invert(lv_obj_t *obj, bool en)

设置线对象Y坐标轴方向是否反转。

启用Y轴反转则绘制时,Y坐标原点(0)将位于对象底部而不是顶部。换言之,Y轴的方向将从下向上增长。

2.12、按钮矩阵 lv_btnmatrix

此控件具有以下特点:

  • 轻量化显示:以行和列方式高效展示多个按钮,它并非实际创建每个独立的按钮对象,而是在运行时按需虚拟绘制。
  • 布局结构:允许开发者以表格形式布局大量按钮,既节省了空间又保持界面清晰,适合于有限屏幕空间下的交互设计,尤其当有大量选项需要用户选择时。
  • 事件处理与导航:添加到按钮矩阵中的所有按钮都会自动加入默认分组。这意味着它们可以响应LVGL的默认事件处理机制,如通过编码器进行导航、选择和点击操作。因此,按钮矩阵不仅支持触摸输入,还支持通过旋钮或编码器等硬件设备进行互动,具有良好的可编辑性。

2.12.1、包含组件元素

  • LV_PART_MAIN:整体背景部分。使用典型的背景样式属性。pad_row pad_column 属性用于设置行间和列间的间距,即不同按钮之间的空白空间大小,以实现更加美观和易用的布局。
  • LV_PART_ITEMS:按钮矩阵中的各个虚拟按钮元素。这些按钮在显示文本时会采用典型的文字样式属性,例如字体、颜色、对齐方式等,但单个按钮不会独立支持移动或旋转这样的几何变换操作,它们的位置是根据矩阵整体布局确定的,并保持相对固定。

2.12.2、相关函数

1、void lv_btnmatrix_set_map(lv_obj_t *obj, const char *map[])

设置按钮矩阵对象的布局映射。通过这个函数,可以动态地创建、删除或重新排列按钮矩阵中的按钮。

参数2字符串数组的指针指向的数组每个字符串代表一个按钮上的文本标签,数组中最后一个元素必须是空字符串 "" 。若要在按钮之间插入换行符以形成多行显示,则在需要换行的位置使用 "\n" 字符。

        const char *button_map[] = {"Button1", "Button2", "\n", "Button3", "Button4", "", ""};

        lv_obj_t *btnmatrix;
        btnmatrix = lv_btnmatrix_create(lv_scr_act());
        lv_obj_set_size(btnmatrix, 200, 150);
        lv_btnmatrix_set_map(btnmatrix, button_map);

 

2、void lv_btnmatrix_set_ctrl_map(lv_obj_t *obj, const lv_btnmatrix_ctrl_t ctrl_map[])

设置按钮矩阵中各个按钮的控制属性。传入的控制映射数组将在函数内部被复制,因此在函数返回后,该数组可以被释放。

参数2数组的长度和元素的位置必须与按钮矩阵中实际按钮的数量和顺序相匹配(不包括换行符符)。数组中的每个元素代表相应按钮的一组控制标志位。

        const char *button_map[] = {"Button1", "Button2", "\n", "Button3", "Button4", "", ""};

        lv_obj_t *btnmatrix;
        btnmatrix = lv_btnmatrix_create(lv_scr_act());
        lv_obj_set_size(btnmatrix, 200, 150);
        lv_btnmatrix_set_map(btnmatrix, button_map);

        //有4个按钮的按钮矩阵,其中前两个按钮是常规按钮,第三个按钮需要被隐藏,第四个按钮应当是切换按钮且不能重复触发
        const lv_btnmatrix_ctrl_t button_ctrls[] =
        {
            0,// 第一个按钮 - 默认情况(无特殊控制)
            0,// 第二个按钮 - 默认情况(无特殊控制)            
            LV_BTNMATRIX_CTRL_HIDDEN,// 第三个按钮 - 隐藏            
            LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_NO_REPEAT// 第四个按钮 - 可切换且禁用重复点击
        };
        // 设置按钮控制映射
        lv_btnmatrix_set_ctrl_map(btnmatrix, button_ctrls);

  • _LV_BTNMATRIX_WIDTH:保留用于存储大小单位的3个最低位。实际使用时不会直接设置这个值,而是通过其他函数来指定按钮宽度。
  • LV_BTNMATRIX_CTRL_HIDDEN:该按钮应被隐藏。
  • LV_BTNMATRIX_CTRL_NO_REPEAT:按钮在按下期间将不会重复触发事件。
  • LV_BTNMATRIX_CTRL_DISABLED:按钮处于禁用状态,用户无法与其交互。
  • LV_BTNMATRIX_CTRL_CHECKABLE:按钮可以切换状态,例如复选框或单选按钮。
  • LV_BTNMATRIX_CTRL_CHECKED:按钮是被选中或激活状态。
  • LV_BTNMATRIX_CTRL_CLICK_TRIG:如果设置为1,则在点击(CLICK)时发送LV_EVENT_VALUE_CHANGE事件;如果设置为0,则在按压(PRESS)时发送。
  • LV_BTNMATRIX_CTRL_POPOVER:当按下该按钮时显示一个弹出窗口(Popover)。
  • LV_BTNMATRIX_CTRL_RECOLOR:启用文本颜色重绘功能,允许使用#color格式动态改变文本颜色。
  • _LV_BTNMATRIX_CTRL_RESERVED:保留供未来使用的位。
  • LV_BTNMATRIX_CTRL_CUSTOM_1 LV_BTNMATRIX_CTRL_CUSTOM_2:这两个标志位可供开发者自定义用途。

     void lv_btnmatrix_set_btn_ctrl(lv_obj_t *obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl)

设置按钮矩阵中单个按钮的控制属性。参数2是按钮在矩阵中的索引。

     void lv_btnmatrix_clear_btn_ctrl(lv_obj_t *obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl)

清除按钮矩阵中特定的控制属性。参数2是按钮在矩阵中的索引。参数3是要清除的按钮属性。

     void lv_btnmatrix_set_btn_ctrl_all(lv_obj_t *obj, lv_btnmatrix_ctrl_t ctrl)

设置按钮矩阵中所有按钮的控制属性。

     void lv_btnmatrix_clear_btn_ctrl_all(lv_obj_t *obj, lv_btnmatrix_ctrl_t ctrl)

清除按钮矩阵中所有按钮的控制属性。

     bool lv_btnmatrix_has_btn_ctrl(lv_obj_t *obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl)

某个按钮是否启用了某个控制属性。

3、void lv_btnmatrix_set_selected_btn(lv_obj_t *obj, uint16_t btn_id)

设置按钮矩阵中被选中的按钮。参数2表示要修改其选中状态的按钮的索引值。

4、void lv_btnmatrix_set_btn_width(lv_obj_t *obj, uint16_t btn_id, uint8_t width)

置按钮矩阵中单个按钮的相对宽度。

参数3是相对宽度值,表示相对于同一行内其他按钮的宽度比例。这个范围是[1,7],其中1表示与同排其他按钮等宽,2则表示宽度为其两倍,以此类推。

        const char *button_map[] = {"Button1", "Button2", "Button3", "\n", "Button4", "Button5", "Button6", ""};

        lv_obj_t *btnmatrix = lv_btnmatrix_create(lv_scr_act());
        lv_obj_set_size(btnmatrix, 400, 150);
        lv_btnmatrix_set_map(btnmatrix, button_map);
        lv_btnmatrix_set_btn_width(btnmatrix, 1, 2); // “Button2”的宽度是其同一行内其他按钮的两倍

5、void lv_btnmatrix_set_one_checked(lv_obj_t *obj, bool en)

设置按钮矩阵在任何时候只能有一个按钮处于选中状态。

要使某些按钮可以被选中,需要先启用 LV_BTNMATRIX_CTRL_CHECKABLE 属性。

        const char *button_map[] = {"Button1", "Button2", "Button3", "\n", "Button4", "Button5", "Button6", ""};

        lv_obj_t *btnmatrix = lv_btnmatrix_create(lv_scr_act());
        lv_obj_set_size(btnmatrix, 400, 150);
        lv_btnmatrix_set_map(btnmatrix, button_map);
        lv_btnmatrix_set_one_checked(btnmatrix, true);
        lv_btnmatrix_set_btn_ctrl_all(btnmatrix,LV_BTNMATRIX_CTRL_CHECKABLE);
        lv_btnmatrix_clear_btn_ctrl(btnmatrix,2,LV_BTNMATRIX_CTRL_CHECKABLE);

6、uint16_t lv_btnmatrix_get_selected_btn(const lv_obj_t *obj)

获取用户最后一次操作(按下、释放、聚焦等)的按钮在按钮矩阵中的索引。此函数在事件回调函数中特别有用。

如果尚未设置或没有按钮被操作过,则返回 LV_BTNMATRIX_BTN_NONE

2.12.3、一个例子

此例来着百问网。 

static void event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);
    uint32_t id = lv_btnmatrix_get_selected_btn(obj);
    bool prev = id == 0 ? true : false;
    bool next = id == 6 ? true : false;
    if(prev || next)
    {
        //查找当前按下的按钮
        uint32_t i;
        for(i = 1; i < 7; ++i)
        {
            if(lv_btnmatrix_has_btn_ctrl(obj, i, LV_BTNMATRIX_CTRL_CHECKED))
                break;
        }

        if(prev && i > 1)
            --i;
        else if(next && i < 5)
            ++i;

        lv_btnmatrix_set_btn_ctrl(obj, i, LV_BTNMATRIX_CTRL_CHECKED);
    }
}

int main(int argc, char **argv)
{
    lv_init();

    hal_init();

    // lv_log_register_print_cb(esp32_log_cb);

    {
        static lv_style_t style_bg;
        lv_style_init(&style_bg);

        lv_style_set_pad_all(&style_bg, 0);// 内边距(上下左右)为0
        lv_style_set_pad_gap(&style_bg, 0);// 间隔也为0
        lv_style_set_clip_corner(&style_bg, true);// 开启圆角剪裁(使内容适应圆形或圆角区域)
        lv_style_set_radius(&style_bg, LV_RADIUS_CIRCLE);// 完全圆形(所有角落的半径均为最大值)
        lv_style_set_border_width(&style_bg, 0);//无边框

        static lv_style_t style_btn;
        lv_style_init(&style_btn);
        lv_style_set_radius(&style_btn, 0);// 直角
        lv_style_set_border_width(&style_btn, 1);//边框宽度为1
        lv_style_set_border_opa(&style_btn, LV_OPA_50);// 边框不透明度为LV_OPA_50(半透明效果)
        lv_style_set_border_color(&style_btn, lv_palette_main(LV_PALETTE_GREY));// 边框颜色为主灰色调(从LV_PALETTE_GREY色彩板获取)
        lv_style_set_border_side(&style_btn, LV_BORDER_SIDE_INTERNAL);//边框在内部显示(相对于内容)

        static const char * map[] = {LV_SYMBOL_LEFT, "1", "2", "3", "4", "5", LV_SYMBOL_RIGHT, ""};

        lv_obj_t * btnm = lv_btnmatrix_create(lv_scr_act());
        lv_btnmatrix_set_map(btnm, map);
        lv_obj_set_size(btnm, 225, 35);
        
        lv_obj_add_style(btnm, &style_bg, LV_PART_MAIN);
        lv_obj_add_style(btnm, &style_btn, LV_PART_ITEMS);
        
        lv_obj_add_event_cb(btnm, event_cb, LV_EVENT_VALUE_CHANGED, NULL);
        
        // 允许按钮矩阵上的按钮可以被选中(单选模式),但取消左侧和右侧箭头按钮的可选状态
        lv_btnmatrix_set_btn_ctrl_all(btnm, LV_BTNMATRIX_CTRL_CHECKABLE);
        lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); // 取消左侧箭头按钮的可选状态
        lv_btnmatrix_clear_btn_ctrl(btnm, 6, LV_BTNMATRIX_CTRL_CHECKABLE); // 取消右侧箭头按钮的可选状态
        
        // 启用按钮矩阵的“单选”模式,确保任何时候只有一个按钮处于选中状态
        lv_btnmatrix_set_one_checked(btnm, true);
        
        // 设置按钮矩阵中的第二个按钮(索引从0开始,所以这里是"1"按钮)为默认选中状态
        lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED);        
        lv_obj_center(btnm);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

2.13、表 lv_table

2.13.1、包含组件元素

  • LV_PART_MAIN:背景。
  • LV_PART_ITEMS:单元格。

2.13.2、相关函数

1、void lv_table_set_cell_value(lv_obj_t *obj, uint16_t row, uint16_t col, const char *txt)

设置表格对象中指定单元格的值。

如果需要的话,当设置超出当前表格大小范围的单元格时,新的行或列会自动添加。

        // 创建一个LVGL表格对象
        lv_obj_t *table = lv_table_create(lv_scr_act());

        // 设置表格的行数和列数(例如,3行4列)
        lv_table_set_row_cnt(table, 3);
        lv_table_set_col_cnt(table, 4);

        // 设置各单元格的值
        lv_table_set_cell_value(table, 0, 0, "Name");
        lv_table_set_cell_value(table, 0, 1, "Age");
        lv_table_set_cell_value(table, 0, 2, "City");
        lv_table_set_cell_value(table, 0, 3, "Country");

        // 填充一些示例数据
        lv_table_set_cell_value(table, 1, 0, "John Doe");
        lv_table_set_cell_value(table, 1, 1, "35");
        lv_table_set_cell_value(table, 1, 2, "New York");
        lv_table_set_cell_value(table, 1, 3, "USA");

        lv_table_set_cell_value(table, 2, 0, "Jane Smith");
        lv_table_set_cell_value(table, 2, 1, "28");
        lv_table_set_cell_value(table, 2, 2, "London");
        lv_table_set_cell_value(table, 2, 3, "UK");

        lv_obj_center(table);

     void lv_table_set_cell_value_fmt(lv_obj_t *obj, uint16_t row, uint16_t col, const char *fmt, ...)

设置表格对象中指定单元格的值,类似于 printf() 函数的方式格式化输出文本。

        lv_obj_t *table = lv_table_create(lv_scr_act());
        lv_table_set_col_cnt(table, 2);

        int age = 25;
        const char *name = "John Doe";
        lv_table_set_cell_value_fmt(table, 0, 0, "%d years old: %s", age, name);

        lv_table_set_cell_value_fmt(table, 1, 1, "%.2f°C", 23.5678f);
        lv_obj_center(table);

 2、void lv_table_set_col_width(lv_obj_t *obj, uint16_t col_id, lv_coord_t w)

设置表格对象中指定列的宽度。

表格组件的高度是由其内容(单元格内的文本高度)和可能的边距、内边距等样式属性决定的,并且自动适应内容。由于表格是基于文本行进行布局的,每一行的高度默认根据当前字体大小及行间距来计算,因此不需要单独设置每行的高度

如果想调整整个表格的整体高度,可以使用 lv_obj_set_height() 函数;如果想增加内容与内容之间的垂直间距从而间接影响行间距,可以通过修改对象的样式属性如 lv_style_set_pad_top/bottom()来实现。

3、void lv_table_add_cell_ctrl(lv_obj_t *obj, uint16_t row, uint16_t col, lv_table_cell_ctrl_t ctrl)

向表格对象的单元格添加控制位。这些控制位定义了单元格的特定属性或行为。

  • LV_TABLE_CELL_CTRL_MERGE_RIGHT:单元格内容将与其右侧相邻的单元格合并显示。即右边界与右侧单元格左边界对齐,中间无分隔线。
  • LV_TABLE_CELL_CTRL_TEXT_CROP:单元格中的文本内容在超出单元格宽度时会被裁剪以适应单元格大小,而不是换行或者溢出。
  • LV_TABLE_CELL_CTRL_CUSTOM_1LV_TABLE_CELL_CTRL_CUSTOM_4:这四个枚举值预留作为自定义用途。

     void lv_table_clear_cell_ctrl(lv_obj_t *obj, uint16_t row, uint16_t col, lv_table_cell_ctrl_t ctrl)

清除表格对象中单元格的控制位。

     bool lv_table_has_cell_ctrl(lv_obj_t *obj, uint16_t row, uint16_t col, lv_table_cell_ctrl_t ctrl)

检查表格对象中的单元格是否设置了指定的控制位。

4、void lv_table_get_selected_cell(lv_obj_t *obj, uint16_t *row, uint16_t *col)

获取表格中当前被选中的单元格,这里的“选中”指的是已被按下或聚焦的状态。

uint16_t selected_row;
uint16_t selected_col;

lv_obj_t *table = ...;

lv_table_get_selected_cell(table, &selected_row, &selected_col);

if (selected_row != LV_TABLE_CELL_NONE && selected_col != LV_TABLE_CELL_NONE) 
{
    printf("Selected cell is at row %d and column %d.\n", selected_row, selected_col);
} 
else
{
    printf("No cell is currently selected.\n");
}

2.14、输入框 lv_textarea

2.14.1、包含组件元素

  • LV_PART_MAIN:背景。可以使用所有典型的背景样式属性,并且还支持与文本相关的样式属性,如 text_align,用于设置文本在区域内左对齐、右对齐或居中。
  • LV_PART_SCROLLBAR:滚动条部分,当文本内容过长无法全部显示时,会显示滚动条。
  • LV_PART_SELECTED:选中文本部分。这部分只能使用 text_color(文本颜色)和 bg_color(背景颜色)两个样式属性。
  • LV_PART_CURSOR:光标部分。anim_time 属性用于设置光标的闪烁间隔时间。
  • LV_PART_TEXTAREA_PLACEHOLDER:占位符文本部分。即当文本输入框内无文本时显示的提示信息的部分。

2.14.2、相关函数

1、void lv_textarea_add_char(lv_obj_t *obj, uint32_t c)

向当前光标位置插入一个字符。

     void lv_textarea_add_text(lv_obj_t *obj, const char *txt)

向当前光标位置插入一段以'\0'结束的字符串。

2、void lv_textarea_del_char(lv_obj_t *obj)

从当前光标位置删除左侧的一个字符。

     void lv_textarea_del_char_forward(lv_obj_t *obj)

从当前光标位置删除右侧的一个字符。

3、void lv_textarea_set_placeholder_text(lv_obj_t *obj, const char *txt)

设置占位符文本。当没有输入任何实际文本时,会显示这个占位符文本。

4、void lv_textarea_set_cursor_pos(lv_obj_t *obj, int32_t pos)

设置光标位置。

参数2是新的光标位置,以字符索引表示。如果值为负数,则表示从文本末尾向前计数的位置,例如-1代表最后一个字符前一位。使用预定义宏 LV_TEXTAREA_CURSOR_LAST 可以将光标置于最后一个字符之后。

5、void lv_textarea_set_cursor_click_pos(lv_obj_t *obj, bool en)

启用或禁用通过点击文本来定位光标的特性。

禁用则即使用户点击了的文本,光标也不会自动跳转到点击位置。

6、void lv_textarea_set_password_mode(lv_obj_t *obj, bool en)

启用或禁用密码模式。

7、void lv_textarea_set_one_line(lv_obj_t *obj, bool en)

配置输入框是否只显示单行内容。

8、void lv_textarea_set_accepted_chars(lv_obj_t *obj, const char *list)

设置输入框允许输入的字符列表。只有在该列表中的字符才能被文本区域接受并显示。

参数2指向一个以空字符'\0'结尾的字符串的指针,这个字符串中包含了允许输入的所有字符。例如,如果只允许输入数字和加减号,可以设置为"0123456789+-"。需要注意的是,这里只是保存了指向字符列表的指针,实际的字符列表会在内存中保留,而不是复制到控件内部。

9、void lv_textarea_set_max_length(lv_obj_t *obj, uint32_t num)

设置允许输入的最大字符数限制。当用户输入的字符数量达到设定值时,将不再接受新的字符输入。需要注意的是,lv_textarea_set_text() 函数在设置文本内容时会忽略这个最大长度限制。

10、void lv_textarea_set_insert_replace(lv_obj_t *obj, const char *txt)

设置插入替换行为。当触发 LV_EVENT_INSERT 事件时,原本计划插入的文本可以通过此函数被替换为另一个文本。这种机制可以用于实现自动格式化文本内容。

参数2如果为空字符串"",则不会添加任何文本。需要注意的是,这个变量必须在事件回调函数执行完毕之后仍然有效,建议将其声明为全局或静态变量以确保生命周期。

如果键盘按下字母A则替换成-A-:

void insert_event_handler(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);
    if(code == LV_EVENT_INSERT)
    {
        if(char * wantToInsertText = (char*)lv_event_get_param(e))
        {
            LV_LOG_USER("wantToInsertText = %s : ", wantToInsertText);

            if(strcmp(wantToInsertText, "a") == 0)
            {
                lv_obj_t * obj = lv_event_get_target(e);
                static const char * txt{"-A-"};
                lv_textarea_set_insert_replace(obj,txt);
            }
        }
    }
}

int main(int argc, char **argv)
{
    lv_init();

    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        lv_obj_t * textarea = lv_textarea_create(lv_scr_act());
        lv_obj_add_event_cb(textarea, insert_event_handler, LV_EVENT_INSERT, NULL);
        lv_obj_center(textarea);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

11、void lv_textarea_set_text_selection(lv_obj_t *obj, bool en)

启用或禁用选择模式。禁用则即使用户尝试操作也无法选中任何文本内容。

      void lv_textarea_clear_selection(lv_obj_t *obj)

取消所有已选中文本的高亮显示,并移除文本的选择状态。

12、void lv_textarea_set_password_show_time(lv_obj_t *obj, uint16_t time)

设置输入框中密码显示的持续时间,当以密码模式工作时,在用户输入字符后,字符将会在指定的时间内以明文形式显示,然后自动变为星号(*)隐藏。单位为毫秒。

13、lv_obj_t *lv_textarea_get_label(const lv_obj_t *obj)

用于对象内部关联的标签对象。本组件是基于标签组件构建的。

14、void lv_textarea_cursor_right(lv_obj_t *obj)

       void lv_textarea_cursor_left(lv_obj_t *obj)

       void lv_textarea_cursor_down(lv_obj_t *obj)

       void lv_textarea_cursor_up(lv_obj_t *obj)

将光标向上 / 下移动一行 、 左 / 右移动一个字符。

2.15、画布 lv_canvas

画布是一个从 lv_img 组件派生出来的高级组件,提供了一个可自定义绘图区域,允许用户在其上绘制各种图形和文本内容。不同于普通的静态图像显示,此组件是一个交互式的画布,可以在其中动态创建和修改内容。

2.15.1、包含组件元素

  • LV_PART_MAIN:背景。

2.15.2、相关函数

1、void lv_canvas_set_buffer(lv_obj_t *canvas, void *buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)

设置缓冲区。

关于缓冲区:

  • 画布的缓冲区是存储画布上所有像素信息的内存区域。
  • 缓冲区的尺寸由画布的宽度、高度以及使用的颜色格式决定。
  • 缓冲区可以被动态或静态地分配内存。
  • 设置缓冲区后,开发者可以直接通过Canvas API对缓冲区内的像素进行读写操作,实现离屏绘制或者高效的图形更新。
  • 使用缓冲区的一个好处是可以预先填充好图像数据,然后一次性设置给Canvas,避免重复绘制带来的性能损耗。
int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    // 首先,定义缓冲区大小并动态分配内存
    lv_coord_t canvas_width = 200;
    lv_coord_t canvas_height = 300;
    lv_img_cf_t color_format = LV_IMG_CF_TRUE_COLOR ; // ARGB8888格式

    // 计算所需缓冲区字节数
    size_t buffer_size = lv_img_cf_get_px_size(color_format) * canvas_width / 8 * canvas_height;

    std::unique_ptr<unsigned char[]> buffer(new unsigned char[buffer_size]);

    lv_obj_t *canvas = nullptr;
    if (buffer)
    {
        canvas = lv_canvas_create(lv_scr_act());
        lv_canvas_set_buffer(canvas, buffer.get(), canvas_width, canvas_height, color_format);

        if(canvas)
        {
            lv_color_t red = lv_color_make(0xff,0x00,0x00);
            lv_draw_rect_dsc_t rect_dsc;
            lv_draw_rect_dsc_init(&rect_dsc);
            rect_dsc.bg_color = red;

            // 绘制一个填充的红色矩形
            lv_canvas_draw_rect(canvas, 50,50,100,75, &rect_dsc);
        }
    }
    else
    {
        LV_LOG_USER("Failed to allocate memory for the canvas buffer");
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

这里缓冲区有三种动态管理内存的方法:

  • 使用lvgl内置的管理函数:
            void *buffer = lv_mem_alloc(buffer_size); // 分配内存
            lv_mem_free(buffer);//释放
  • new / delete:

            unsigned char* buffer = new unsigned char[buffer_size]; 
            delete [] buffer;
  • 智能指针

            std::unique_ptr<unsigned char[]> buffer(new unsigned char[buffer_size]); 

2、void lv_canvas_set_px_color(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, lv_color_t c)

设置画布上指定坐标点的像素颜色。

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    // 定义缓冲区大小并动态分配内存
    lv_coord_t canvas_width = 200;
    lv_coord_t canvas_height = 300;
    lv_img_cf_t color_format = LV_IMG_CF_TRUE_COLOR ; // ARGB8888格式    
    size_t buffer_size = lv_img_cf_get_px_size(color_format) * canvas_width / 8 * canvas_height;// 计算所需缓冲区字节数

    std::unique_ptr<unsigned char[]> buffer(new unsigned char[buffer_size]);

    lv_obj_t *canvas = nullptr;
    if (buffer)
    {
        canvas = lv_canvas_create(lv_scr_act());
        lv_canvas_set_buffer(canvas, buffer.get(), canvas_width, canvas_height, color_format);

        if(canvas)
        {
            lv_color_t red = lv_color_make(0xff,0x00,0x00);
            lv_draw_rect_dsc_t rect_dsc;
            lv_draw_rect_dsc_init(&rect_dsc);
            rect_dsc.bg_color = red;

            for(int i = 50;i < 80;++i)
            {
                lv_canvas_set_px_color(canvas, 50, i, red);
            }
        }
    }
    else
    {
        LV_LOG_USER("Failed to allocate memory for the canvas buffer");
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

     void lv_canvas_set_px(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, lv_color_t c)

3、void lv_canvas_set_px_opa(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, lv_opa_t opa)

设置画布上指定坐标点像素不透明度。

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    // 定义缓冲区大小并动态分配内存
    lv_coord_t canvas_width = 200;
    lv_coord_t canvas_height = 300;
    lv_img_cf_t color_format = LV_IMG_CF_TRUE_COLOR_ALPHA ;
    size_t buffer_size = lv_img_cf_get_px_size(color_format) * canvas_width / 8 * canvas_height;// 计算所需缓冲区字节数

    std::unique_ptr<unsigned char[]> buffer(new unsigned char[buffer_size]);

    lv_obj_t *canvas = nullptr;
    if (buffer)
    {
        canvas = lv_canvas_create(lv_scr_act());
        lv_canvas_set_buffer(canvas, buffer.get(), canvas_width, canvas_height, color_format);

        if(canvas)
        {
            lv_color_t red = lv_color_make(0xff,0x00,0x00);
            lv_draw_rect_dsc_t rect_dsc;
            lv_draw_rect_dsc_init(&rect_dsc);
            rect_dsc.bg_color = red;

            for(int i = 100;i < 150;++i)
            {
                for(int j = 100;j < 150;++j)
                {
                    lv_canvas_set_px_color(canvas,i,j,red);
                    lv_canvas_set_px_opa(canvas, j, i, LV_OPA_80);
                }
            }

            for(int i = 50;i < 80;++i)
            {
                for(int j = 50;j < 80;++j)
                {
                    lv_canvas_set_px_opa(canvas, j, i, LV_OPA_50);
                    lv_canvas_set_px_color(canvas,j,i,red);
                }
            }
        }
    }
    else
    {
        LV_LOG_USER("Failed to allocate memory for the canvas buffer");
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

4、void lv_canvas_set_palette(lv_obj_t *canvas, uint8_t id, lv_color_t c)

设置调色板颜色。这个函数仅适用于使用索引颜色格式的画布,具体来说是:

  • LV_IMG_CF_INDEXED1:调色板支持2种颜色
  • LV_IMG_CF_INDEXED2:调色板支持4种颜色
  • LV_IMG_CF_INDEXED4:调色板支持16种颜色
  • LV_IMG_CF_INDEXED8:调色板支持256种颜色

参数2调色板颜色索引值。根据不同的索引颜色格式,这个值的范围不同:

  • LV_IMG_CF_INDEXED1:有效范围是 0 到 1。
  • LV_IMG_CF_INDEXED2:有效范围是 0 到 3。
  • LV_IMG_CF_INDEXED4:有效范围是 0 到 15。
  • LV_IMG_CF_INDEXED8:有效范围是 0 到 255。
int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    lv_obj_t *canvas = lv_canvas_create(lv_scr_act());

    // 定义一个静态颜色缓冲区,大小根据50x50像素、1位索引色格式计算得出
    static lv_color_t cbuf[LV_CANVAS_BUF_SIZE_INDEXED_1BIT(50, 50)];
    // 将颜色缓冲区关联到画布,设置画布尺寸为50x50像素,并指定颜色格式为1位索引色
    lv_canvas_set_buffer(canvas, cbuf, 50, 50, LV_IMG_CF_INDEXED_1BIT);

    lv_canvas_set_palette(canvas, 0, lv_palette_main(LV_PALETTE_YELLOW));// 设置画布调色板,索引0对应的颜色为黄色(从LVGL内置调色板获取)
    lv_canvas_set_palette(canvas, 1, lv_palette_main(LV_PALETTE_BLUE));  // 设置画布调色板,索引1对应的颜色为蓝色(同样从LVGL内置调色板获取)

    // 两个颜色变量:c1代表索引1(在1位索引模式下代表前景色),c0代表索引0(背景色)
    lv_color_t c1;
    lv_color_t c0;

    c1.full = 1;// 设置c1为索引1,即使用前景色
    c0.full = 0;// 设置c0为索引0,即使用背景色

    // 填充画布背景为黄色(虽然在1位索引图像中没有专用透明度通道,但LV_OPA_COVER用于确保完全覆盖)
    lv_canvas_fill_bg(canvas, c1, LV_OPA_COVER);

    // 在画布中心创建一个25x25像素的黑色区域,通过逐点设置索引0的颜色
    uint32_t x;
    uint32_t y;
    for(y = 0; y < 25; y++)
    {
        for(x = 0; x < 25; x++)
        {
            lv_canvas_set_px(canvas, x, y, c0);
        }
    }

    while (1)
    {
        lv_task_handler(); // 处理LVGL任务队列中的事件
        usleep(5 * 1000); // 暂停5毫秒,让操作系统进行其他操作
    }

    return 0;
}

5、lv_img_dsc_t *lv_canvas_get_img(lv_obj_t *canvas)

获取画布对象的图像描述符。

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    lv_coord_t canvas_width = 100;
    lv_coord_t canvas_height = 100;
    lv_img_cf_t color_format = LV_IMG_CF_TRUE_COLOR ;
    size_t buffer_size = lv_img_cf_get_px_size(color_format) * canvas_width / 8 * canvas_height;// 计算所需缓冲区字节数

    std::unique_ptr<unsigned char[]> buffer(new unsigned char[buffer_size]);

    if (buffer)
    {
        lv_obj_t *canvas = lv_canvas_create(lv_scr_act());
        lv_canvas_set_buffer(canvas, buffer.get(), canvas_width, canvas_height, color_format);

        if(canvas)
        {
            lv_color_t red = lv_color_make(0xff,0x00,0x00);
            lv_draw_rect_dsc_t rect_dsc;
            lv_draw_rect_dsc_init(&rect_dsc);
            rect_dsc.bg_color = red;

            for(int i = 20;i < 40;++i)
            {
                for(int j = 20;j < 40;++j)
                {
                    lv_canvas_set_px_color(canvas,i,j,red);
                }
            }

            lv_img_dsc_t * img = lv_canvas_get_img(canvas);
            lv_obj_t * imgobj = lv_img_create(lv_scr_act());
            lv_img_set_src(imgobj,img);
            lv_obj_center(imgobj);
        }
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

6、void lv_canvas_copy_buf(lv_obj_t *canvas, const void *to_copy, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h)

将指定的缓冲区内容复制到画布对象上指定的位置。

x、y是在画布上复制图像的坐标位置。

w、h是要复制的缓冲区的尺寸。

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    lv_coord_t canvas_width = 300;
    lv_coord_t canvas_height = 300;
    lv_img_cf_t color_format = LV_IMG_CF_TRUE_COLOR ;
    size_t buffer_size = lv_img_cf_get_px_size(color_format) * canvas_width / 8 * canvas_height;// 计算所需缓冲区字节数

    std::unique_ptr<unsigned char[]> buffer(new unsigned char[buffer_size]);

    if (buffer)
    {
        lv_obj_t *canvas = lv_canvas_create(lv_scr_act());
        lv_canvas_set_buffer(canvas, buffer.get(), canvas_width, canvas_height, color_format);

        if(canvas)
        {
            lv_color_t red = lv_color_make(0xff,0x00,0x00);
            lv_draw_rect_dsc_t rect_dsc;
            lv_draw_rect_dsc_init(&rect_dsc);
            rect_dsc.bg_color = red;

            for(int i = 120;i < 140;++i)
            {
                for(int j = 120;j < 140;++j)
                {
                    lv_canvas_set_px_color(canvas,i,j,red);
                }
            }

            //图像解码器
            lv_img_decoder_t *lv_img_decoder = lv_img_decoder_create();
            lv_img_decoder_set_info_cb(lv_img_decoder, lv_img_decoder_built_in_info);
            lv_img_decoder_set_open_cb(lv_img_decoder, lv_img_decoder_built_in_open);
            lv_img_decoder_set_read_line_cb(lv_img_decoder, lv_img_decoder_built_in_read_line);
            lv_img_decoder_set_close_cb(lv_img_decoder, lv_img_decoder_built_in_close);

            const void *image_source = "M:huaji.png"; // 图片路径

            _lv_img_decoder_dsc_t img_dsc;

            // 打开并读取图像文件头信息
            lv_res_t res = lv_img_decoder_open(&img_dsc, image_source, lv_color_make(0xff,0xff,0xff),0);
            if(res == LV_RES_OK)// 图片已成功解码
            {
                lv_canvas_copy_buf(canvas, img_dsc.img_data, 10, 10, img_dsc.header.w, img_dsc.header.h);
                lv_canvas_copy_buf(canvas, img_dsc.img_data, 10, 120, img_dsc.header.w / 2, img_dsc.header.h);

                lv_img_decoder_close(&img_dsc);// 关闭解码器和释放资源
            }
            lv_img_decoder_delete(lv_img_decoder);            // 删除解码器
        }
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

貌似尺寸要图片实际尺寸一样,还是和图片格式有关?

7、void lv_canvas_transform(lv_obj_t *canvas, lv_img_dsc_t *img, int16_t angle, uint16_t zoom, lv_coord_t offset_x, lv_coord_t offset_y, int32_t pivot_x, int32_t pivot_y, bool antialias)

将图像进行旋转、缩放和偏移操作,并将变换后的内容存储到指定的画布对象上。

  • angle:旋转角度,范围为0至3600,单位为0.1度。例如,360表示旋转36度。
  • zoom:缩放因子,默认值256代表不缩放。大于256则放大,小于256则缩小。
  • offset_xoffset_y:在目标canvas上放置变换结果时的水平和垂直偏移量,决定了变换后图像在canvas中的位置。
  • pivot_xpivot_y:旋转中心点坐标,相对于源图像的坐标系。设置为源图像宽度的一半和高度的一半可使图像绕其中心旋转。
  • antialias:是否应用抗锯齿处理。

例1: 

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    // lv_example_canvas_1();
    const int canvas_width = 200;
    const int canvas_height = 200;
    lv_img_cf_t color_format = LV_IMG_CF_TRUE_COLOR;

    {
        lv_obj_t *canvas = lv_canvas_create(lv_scr_act());
        static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(canvas_width, canvas_height)];
        lv_canvas_set_buffer(canvas, buffer, canvas_width, canvas_height, color_format);

        //图像解码器
        lv_img_decoder_t *lv_img_decoder = lv_img_decoder_create();
        lv_img_decoder_set_info_cb(lv_img_decoder, lv_img_decoder_built_in_info);
        lv_img_decoder_set_open_cb(lv_img_decoder, lv_img_decoder_built_in_open);
        lv_img_decoder_set_read_line_cb(lv_img_decoder, lv_img_decoder_built_in_read_line);
        lv_img_decoder_set_close_cb(lv_img_decoder, lv_img_decoder_built_in_close);

        const void *image_source = "M:huaji.png"; // 图片路径

        _lv_img_decoder_dsc_t img_decoder_dsc;

        // 打开并读取图像文件头信息
        lv_res_t res = lv_img_decoder_open(&img_decoder_dsc, image_source, lv_color_make(0xff,0xff,0xff),0);
        if(res == LV_RES_OK)// 图片已成功解码
        {
            static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(canvas_width, canvas_height)];
            lv_canvas_set_buffer(canvas, buffer, canvas_width, canvas_height, color_format);

            lv_img_dsc_t img_dsc;
            img_dsc.data =  img_decoder_dsc.img_data;
            img_dsc.header.cf = color_format;    // 图像格式
            img_dsc.header.w = img_decoder_dsc.header.w; // 图像宽度
            img_dsc.header.h = img_decoder_dsc.header.h; // 图像高度

            lv_canvas_transform(canvas,
                                &img_dsc,
                                450,                 //旋转450度
                                LV_IMG_ZOOM_NONE * 0.8,    // LV_IMG_ZOOM_NONE = 256
                                0, 0,
                                canvas_width / 2, canvas_height / 2,
                                true);// 以画布中心为原点,旋转30度

            lv_img_decoder_close(&img_decoder_dsc);// 关闭并释放资源
        }
        lv_img_decoder_delete(lv_img_decoder);            // 删除解码器
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

例2:

变换之前:

    lv_draw_rect_dsc_t rect_dsc;
    lv_draw_rect_dsc_init(&rect_dsc);// 初始化矩形样式描述符

    rect_dsc.radius = 10;// 设置矩形圆角半径
    rect_dsc.bg_opa = LV_OPA_COVER; // 背景不透明度为完全不透明
    rect_dsc.bg_grad_dir = LV_GRAD_DIR_HOR; // 水平渐变
    rect_dsc.bg_color = lv_color_make(0xff,0x00,0x00); // 红色背景
    rect_dsc.bg_grad_color = lv_color_make(0x00,0xff,0x00); // 绿色渐变背景

    rect_dsc.border_width = 2; // 边框宽度
    rect_dsc.border_opa = LV_OPA_90; // 边框不透明度为90%
    rect_dsc.border_color = lv_color_make(0xff,0xff,0xff); // 白色边框

    rect_dsc.shadow_width = 5; // 阴影宽度为5像素
    rect_dsc.shadow_ofs_x = 5; // 阴影在X轴偏移5像素
    rect_dsc.shadow_ofs_y = 5; // 阴影在Y轴偏移5像素

    const int CANVAS_WIDTH = 200;
    const int CANVAS_HEIGHT = 150;

    lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
    lv_obj_center(canvas);

    // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
    static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
    lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);

    lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);
    lv_canvas_draw_rect(canvas, 70, 60, 100, 70, &rect_dsc);// 在Canvas上绘制一个矩形

    {
        lv_color_t red = lv_color_make(0xff,0x00,0x00);
        lv_draw_rect_dsc_t rect_dsc;
        lv_draw_rect_dsc_init(&rect_dsc);
        rect_dsc.bg_color = red;

        for(int i = 20;i < 25;++i)
        {
            for(int j = 20;j < 100;++j)
            {
                lv_canvas_set_px_color(canvas,i,j,red);
            }
        }
    }

变换后:

    lv_draw_rect_dsc_t rect_dsc;
    lv_draw_rect_dsc_init(&rect_dsc);// 初始化矩形样式描述符

    rect_dsc.radius = 10;// 设置矩形圆角半径
    rect_dsc.bg_opa = LV_OPA_COVER; // 背景不透明度为完全不透明
    rect_dsc.bg_grad_dir = LV_GRAD_DIR_HOR; // 水平渐变
    rect_dsc.bg_color = lv_color_make(0xff,0x00,0x00); // 红色背景
    rect_dsc.bg_grad_color = lv_color_make(0x00,0xff,0x00); // 绿色渐变背景

    rect_dsc.border_width = 2; // 边框宽度
    rect_dsc.border_opa = LV_OPA_90; // 边框不透明度为90%
    rect_dsc.border_color = lv_color_make(0xff,0xff,0xff); // 白色边框

    rect_dsc.shadow_width = 5; // 阴影宽度为5像素
    rect_dsc.shadow_ofs_x = 5; // 阴影在X轴偏移5像素
    rect_dsc.shadow_ofs_y = 5; // 阴影在Y轴偏移5像素

    const int CANVAS_WIDTH = 200;
    const int CANVAS_HEIGHT = 150;

    lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
    lv_obj_center(canvas);

    // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
    static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
    lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);

    lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);
    lv_canvas_draw_rect(canvas, 70, 60, 100, 70, &rect_dsc);// 在Canvas上绘制一个矩形

    {
        lv_color_t red = lv_color_make(0xff,0x00,0x00);
        lv_draw_rect_dsc_t rect_dsc;
        lv_draw_rect_dsc_init(&rect_dsc);
        rect_dsc.bg_color = red;

        for(int i = 20;i < 25;++i)
        {
            for(int j = 20;j < 100;++j)
            {
                lv_canvas_set_px_color(canvas,i,j,red);
            }
        }
    }

    static lv_color_t buffer_copy[CANVAS_WIDTH * CANVAS_HEIGHT];
    memcpy(buffer_copy, buffer, sizeof(buffer_copy));

    // 将临时缓冲区的数据封装为一个lv_img_dsc_t结构体
    lv_img_dsc_t img;
    img.data = (uint8_t*)buffer_copy;
    img.header.cf = LV_IMG_CF_TRUE_COLOR; // 图像格式为真彩色
    img.header.w = CANVAS_WIDTH; // 图像宽度
    img.header.h = CANVAS_HEIGHT; // 图像高度

    lv_canvas_transform(canvas,
                        &img,
                        450,                 //旋转450度
                        LV_IMG_ZOOM_NONE,   // LV_IMG_ZOOM_NONE = 256
                        0, 0,
                        CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2,
                        true);// 以画布中心为原点,旋转45度

8、void lv_canvas_blur_hor(lv_obj_t *canvas, const lv_area_t *area, uint16_t r)

      void lv_canvas_blur_hor(lv_obj_t *canvas, const lv_area_t *area, uint16_t r)

水平方向 / 垂直方向执行高斯模糊效果,即通过计算一定范围内像素颜色的加权平均值来模拟视觉上的模糊效果。

参数2如果为NULL,则默认对整个画布进行模糊处理。

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        lv_draw_rect_dsc_t rect_dsc;
        lv_draw_rect_dsc_init(&rect_dsc);// 初始化矩形样式描述符

        rect_dsc.radius = 10;// 设置矩形圆角半径
        rect_dsc.bg_opa = LV_OPA_COVER; // 背景不透明度为完全不透明
        rect_dsc.bg_grad_dir = LV_GRAD_DIR_HOR; // 水平渐变
        rect_dsc.bg_color = lv_color_make(0xff,0x00,0x00); // 红色背景
        rect_dsc.bg_grad_color = lv_color_make(0x00,0xff,0x00); // 绿色渐变背景

        rect_dsc.border_width = 2; // 边框宽度
        rect_dsc.border_opa = LV_OPA_90; // 边框不透明度为90%
        rect_dsc.border_color = lv_color_make(0xff,0xff,0xff); // 白色边框

        rect_dsc.shadow_width = 5; // 阴影宽度为5像素
        rect_dsc.shadow_ofs_x = 5; // 阴影在X轴偏移5像素
        rect_dsc.shadow_ofs_y = 5; // 阴影在Y轴偏移5像素

        const int CANVAS_WIDTH = 200;
        const int CANVAS_HEIGHT = 150;

        lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
        lv_obj_center(canvas);

        // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
        static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
        lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);

        lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);
        lv_canvas_draw_rect(canvas, 70, 60, 100, 70, &rect_dsc);// 在Canvas上绘制一个矩形

        // 定义要模糊的区域(这里假设模糊整个Canvas)
        lv_area_t blur_area;
        blur_area.x1 = 70;
        blur_area.y1 = 60;
        blur_area.x2 = 100;
        blur_area.y2 = 150;

        lv_canvas_blur_hor(canvas, &blur_area, 5);
        lv_canvas_blur_ver(canvas, &blur_area, 5);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

9、void lv_canvas_fill_bg(lv_obj_t *canvas, lv_color_t color, lv_opa_t opa);

填充画布的背景颜色。

10、void lv_canvas_draw_rect(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, const lv_draw_rect_dsc_t *draw_dsc);

在画布上绘制一个矩形。

  • x、y、w、h:矩形左上角的坐标、矩形的宽高。
  • draw_dsc:此结构体包含了描绘矩形所需的样式描述信息。

11、void lv_canvas_draw_text(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, lv_coord_t max_w, lv_draw_label_dsc_t *draw_dsc, const char *txt)

在画布上绘制文本。

  • x:文本左边缘的X坐标,以像素为单位。
  • y:文本基线(通常对应于第一行文本底部)的Y坐标,同样以像素为单位。
  • max_w:文本的最大宽度。如果文本长度超过这个值,会自动换行以适应最大宽度。
  • draw_dsc:此结构体包含了描述绘制文本的样式。
int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        const int CANVAS_WIDTH = 300;
        const int CANVAS_HEIGHT = 300;

        lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
        lv_obj_center(canvas);

        // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
        static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
        lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);

        lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);

        // 创建一个文本描述符并设置属性
        lv_draw_label_dsc_t draw_dsc;
        lv_draw_label_dsc_init(&draw_dsc); // 初始化为默认值
        draw_dsc.font = &lv_font_montserrat_28; // 设置字体为28像素大小的Montserrat字体
        draw_dsc.color = lv_color_make(0x00,0xff,0x00); // 设置文字颜色
        draw_dsc.letter_space = 2; // 设置字符间距为2个像素

        // 要绘制的文本内容
        const char *text_to_display = "Hello, World! This is a test text on the canvas.";

        // 在Canvas上指定位置绘制文本,最大宽度为200像素
        lv_coord_t x = 50;
        lv_coord_t y = 50;
        lv_coord_t max_width = 200;

        lv_canvas_draw_text(canvas, x, y, max_width, &draw_dsc, text_to_display);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

12、void lv_canvas_draw_img(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, const void *src, const lv_draw_img_dsc_t *draw_dsc);

在画布上绘制图像。

  • x、y:图像在画布上的坐标。
  • src:图像源。它可以是一个指向 lv_img_dsc_t 结构体变量的指针,代表一个内部存储或动态加载的图像数据;或者也可以是一个包含图像路径的字符串指针,指向外部文件资源
  • draw_dsc:此描述符包含了绘制的样式。
int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        const int CANVAS_WIDTH = 300;
        const int CANVAS_HEIGHT = 300;

        lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
        lv_obj_center(canvas);

        // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
        static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
        lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);

        lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);

        //图像解码器
        lv_img_decoder_t *lv_img_decoder = lv_img_decoder_create();
        lv_img_decoder_set_info_cb(lv_img_decoder, lv_img_decoder_built_in_info);
        lv_img_decoder_set_open_cb(lv_img_decoder, lv_img_decoder_built_in_open);
        lv_img_decoder_set_read_line_cb(lv_img_decoder, lv_img_decoder_built_in_read_line);
        lv_img_decoder_set_close_cb(lv_img_decoder, lv_img_decoder_built_in_close);

        const void *image_source = "M:huaji.png"; // 图片路径

        _lv_img_decoder_dsc_t img_decoder_dsc;

        // 打开并读取图像文件头信息
        lv_res_t res = lv_img_decoder_open(&img_decoder_dsc, image_source, lv_color_make(0xff,0xff,0xff),0);
        if(res == LV_RES_OK)// 图片已成功解码
        {
            static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
            lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);

            lv_canvas_fill_bg(canvas,lv_palette_lighten(LV_PALETTE_LIGHT_BLUE, 3),LV_OPA_30);

            lv_img_dsc_t img_dsc;
            img_dsc.data =  img_decoder_dsc.img_data;
            img_dsc.header.cf = LV_IMG_CF_TRUE_COLOR;    // 图像格式
            img_dsc.header.w = img_decoder_dsc.header.w; // 图像宽度
            img_dsc.header.h = img_decoder_dsc.header.h; // 图像高度

            lv_draw_img_dsc_t draw_dsc;
            lv_draw_img_dsc_init(&draw_dsc); // 初始化描述符
            draw_dsc.opa = LV_OPA_60;//图像透明度

            lv_canvas_draw_img(canvas,
                               20,20,
                               &img_dsc,
                               &draw_dsc);

            lv_img_decoder_close(&img_decoder_dsc);// 关闭并释放资源
        }
        lv_img_decoder_delete(lv_img_decoder);            // 删除解码器
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

或:

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        const int CANVAS_WIDTH = 300;
        const int CANVAS_HEIGHT = 300;

        lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
        lv_obj_center(canvas);

        // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
        static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
        lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
        lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);

        const void *image_source = "M:huaji.png"; // 图片路径

        lv_draw_img_dsc_t draw_dsc;
        lv_draw_img_dsc_init(&draw_dsc); // 初始化描述符
        draw_dsc.opa = LV_OPA_60;//图像透明度

        lv_canvas_draw_img(canvas,
                           20,20,
                           image_source,
                           &draw_dsc);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

13、void lv_canvas_draw_line(lv_obj_t *canvas, const lv_point_t points[], uint32_t point_cnt, const lv_draw_line_dsc_t *draw_dsc)

在画布上绘制一系列相连的线段,可以是一条折线或多条直线构成的路径。

  • point_cnt:点的数量,即points数组中有效坐标的个数。相邻两点之间会绘制一条线段。
  • draw_dsc:绘制线条的样式。
int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        const int CANVAS_WIDTH = 300;
        const int CANVAS_HEIGHT = 300;

        lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
        lv_obj_center(canvas);

        // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
        static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
        lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
        lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);

        lv_point_t line_points[4] =
        {
            {50, 50}, // 第一个点
            {100, 100}, // 第二个点
            {150, 50}, // 第三个点
            {200, 100}  // 第四个点
        };

        lv_draw_line_dsc_t line_dsc;
        lv_draw_line_dsc_init(&line_dsc); // 初始化线段的绘制描述符
        line_dsc.color = lv_palette_lighten(LV_PALETTE_CYAN, 3); // 设置颜色
        line_dsc.width = 3; // 线宽设为3像素

        lv_canvas_draw_line(canvas, line_points, 4, &line_dsc);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

14、void lv_canvas_draw_polygon(lv_obj_t *canvas, const lv_point_t points[], uint32_t point_cnt, const lv_draw_rect_dsc_t *draw_dsc);

绘制多边形。

int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        const int CANVAS_WIDTH = 300;
        const int CANVAS_HEIGHT = 300;

        lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
        lv_obj_center(canvas);

        // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
        static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
        lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
        lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);

        lv_point_t hexagon_points[6] =
        {
            {100, 50},
            {150, 10},
            {200, 50},
            {150, 90},
            {100, 90},
            {50, 50}
        };

        lv_draw_rect_dsc_t polygon_dsc;
        lv_draw_rect_dsc_init(&polygon_dsc);
        polygon_dsc.border_color = lv_palette_lighten(LV_PALETTE_BLUE, 2); // 设置边框颜色
        polygon_dsc.border_width = 2; // 边框宽度
        polygon_dsc.bg_color = lv_palette_lighten(LV_PALETTE_RED, 3);

        lv_canvas_draw_polygon(canvas, hexagon_points, 6, &polygon_dsc);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

15、void lv_canvas_draw_arc(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, lv_coord_t r, int32_t start_angle, int32_t end_angle, const lv_draw_arc_dsc_t *draw_dsc)

绘制圆弧或部分扇形。

  • x、y:圆弧的圆心坐标。
  • r:圆弧的半径。
  • start_angle:起始角度,以度为单位,0度通常定义为正右方向(相当于钟表3点钟位置),顺时针方向增加角度值。
  • end_angle:结束角度,同样以度为单位,表示圆弧终止的位置。如果start_angle和end_angle之间的差值大于360度,则会按照顺时针或逆时针方向绘制超过一圈的部分。
  • draw_dsc:绘制圆弧的样式。
int main(int argc, char **argv)
{
    lv_init();
    hal_init();

    lv_log_register_print_cb(esp32_log_cb);

    {
        const int CANVAS_WIDTH = 300;
        const int CANVAS_HEIGHT = 300;

        lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
        lv_obj_center(canvas);

        // 临时的颜色缓冲区来存储Canvas的真彩色图像数据
        static lv_color_t buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
        lv_canvas_set_buffer(canvas, buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
        lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_BROWN, 3), LV_OPA_COVER);

        lv_draw_arc_dsc_t arc_dsc;
        lv_draw_arc_dsc_init(&arc_dsc); // 使用默认设置初始化
        arc_dsc.color = lv_color_hex(0xFF0000); // 设置线条颜色为红色
        arc_dsc.width = 3;

        lv_obj_update_layout(canvas);

        // 计算圆心位置(这里以Canvas中心为例)
        lv_coord_t x = lv_obj_get_width(canvas) / 2;
        lv_coord_t y = lv_obj_get_height(canvas) / 2;
        lv_coord_t r = lv_obj_get_width(canvas) / 4;

        lv_canvas_draw_arc(canvas, x, y, r, 0, 90, &arc_dsc);
    }

    while (1)
    {
        lv_task_handler();
        usleep(5 * 1000);
    }

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值