LVGL 控件之矩阵按钮(lv_buttonmatrix)

目录


一、矩阵按键

1、组成

按钮矩阵部件由两个部分组成:主体背景和按钮,示意图如下:

  • LV_PART_MAIN:对应按钮矩阵的背景
  • LV_PART_ITEMS:对应按钮矩阵的按钮
c 复制代码
lv_obj_set_style_bg_color(btnM, lv_color_make(152, 244, 123), LV_PART_MAIN);
c 复制代码
lv_obj_set_style_bg_color(btnM, lv_color_make(152, 244, 123), LV_PART_ITEMS);

2、创建矩阵

按钮矩阵部件中的每个按钮都可以设置文本,如果用户想设置这些按钮文本,则需要定义一个字符串数组(指针),并在该数组中传入所需的文本内容,最后通过 lv_btnmatrix_set_map 函数设置按钮文本,示例代码如下:

注意:该数组最后一个元素必须为空

c 复制代码
lv_obj_t *btnM = lv_btnmatrix_create(lv_scr_act());
static const char* btnMap[] = {
    ",", "ABC", "DEF", "\n",
    "GHI", "JKL", "MNO", "\n",
    "PQRS", "TUV", "WXYX", ""
};
lv_btnmatrix_set_map(btnM, btnMap);
lv_obj_align(btnM, LV_ALIGN_CENTER, 0, 0);

此外,每个按钮还有个索引,索引对于按钮的属性设置非常重要。实际上索引的顺序就是我们添加按键的顺序:

3、按钮宽度

在默认情况下,按钮矩阵每一行按钮的宽度都是自动计算的,如果用户想改变按钮的宽度,可以调用 lv_btnmatrix_set_btn_width 函数来进行设置。值得注意的是,在按钮矩阵部件中,按钮只能设置相对宽度。

现在在上例的基础上添加:

c 复制代码
lv_btnmatrix_set_btn_width(btnM, 1, 10);

4、按键属性

用户可以调用 lv_btnmatrix_set_btn_ctrl 函数,为按钮添加、清除指定的属性,这些属性的相关枚举如下:

  • LV_BTNMATRIX_CTRL_HIDDEN:将按钮隐藏;
  • LV_BTNMATRIX_CTRL_NO_REPEAT:禁用长按;
  • LV_BTNMATRIX_CTRL_DISABLED:禁用按钮;
  • LV_BTNMATRIX_CTRL_CHECKABLE:启用按钮状态切换;
  • LV_BTNMATRIX_CTRL_CHECKED:选中按钮;
  • LV_BTNMATRIX_CTRL_POPOVER:按下此按钮时在弹出窗口中显示按钮标签;
  • LV_BTNMATRIX_CTRL_RECOLOR:启用按钮文本的重新着色功能。

例:

c 复制代码
lv_btnmatrix_set_btn_ctrl(btnM, 0, LV_BTNMATRIX_CTRL_HIDDEN);
lv_btnmatrix_set_btn_ctrl(btnM, 1, LV_BTNMATRIX_CTRL_DISABLED);
lv_btnmatrix_set_btn_ctrl(btnM, 2, LV_BTNMATRIX_CTRL_CHECKABLE);

如果用户想要清除按钮的指定属性,可以调用 lv_btnmatrix_clear_btn_ctrl 函数。

5、按钮互斥

按钮互斥是指:在某一时刻,只允许有一个按钮处于按下不弹起状态(被选中),当我们选中一个按钮之后,其他的按钮将会自动清除选中属性,示意图如下:

c 复制代码
lv_btnmatrix_set_btn_ctrl(btnM, 0, LV_BTNMATRIX_CTRL_CHECKABLE);
lv_btnmatrix_set_btn_ctrl(btnM, 1, LV_BTNMATRIX_CTRL_CHECKABLE);
lv_btnmatrix_set_btn_ctrl(btnM, 2, LV_BTNMATRIX_CTRL_CHECKABLE);

lv_btnmatrix_set_one_checked(btnm1, true);

点击第一个键后,其处于被选中状态;

现在再点击第三个键,其处于被选中状态,不过第一个键的状态被清除了:

6、按钮文本重着色

在默认情况下,按钮矩阵中的按钮文本都是黑色的,如果用户需要设置文本为其他的颜色,则必须先调用 lv_btnmatrix_set_btn_ctrl 函数,为按钮添加文本重着色的属性。

设置如下:

c 复制代码
void my_gui(void)
{
    lv_obj_t *btnM = lv_btnmatrix_create(lv_scr_act());
    static const char* btnMap[] = {
        ",", "#FF0000 ABC#", "DEF", "\n",
        "GHI", "JKL", "MNO", "\n",
        "PQRS", "TUV", "WXYX", ""
    };
    lv_btnmatrix_set_map(btnM, btnMap);
    lv_obj_align(btnM, LV_ALIGN_CENTER, 0, 0);

    lv_btnmatrix_set_btn_ctrl(btnM, 1, LV_BTNMATRIX_CTRL_RECOLOR);
}

注意看,颜色设置格式为:# + 16 进制颜色 + 按钮文本 + #,在设置完文本颜色之后,我们还需要为按钮添加文本重着色的属性,其相关的枚举为 LV_BTNMATRIX_CTRL_RECOLOR

7、按钮矩阵部件的事件

  1. LV_EVENT_VALUE_CHANGED:当一个按钮被按下、释放或长按时发送。
  2. LV_EVENT_DRAW_PART_BEGIN:开始绘制按钮。

8、API 函数

函数 含义
lv_btnmatrix_create() 创建按钮矩阵部件
lv_btnmatrix_set_map() 设置按钮
lv_btnmatrix_set_ctrl_map() 设置多个按钮属性
lv_btnmatrix_set_selected_btn() 设置选中的按钮
lv_btnmatrix_set_btn_ctrl() 设置一个按钮的属性
lv_btnmatrix_clear_btn_ctrl() 清除某个按钮的属性
lv_btnmatrix_set_btn_ctrl_all() 设置所有按钮的属性
lv_btnmatrix_clear_btn_ctrl_all() 清除所有按钮的属性
lv_btnmatrix_set_btn_width() 设置单个按钮的相对宽度
lv_btnmatrix_set_one_checked() 设置按钮互斥
lv_btnmatrix_get_map() 获取按钮相关映射
lv_btnmatrix_get_selected_btn() 获取用户最后点击的按钮的索引
lv_btnmatrix_get_btn_text() 获取按钮的文本
lv_btnmatrix_has_btn_ctrl() 获取按钮的状态
lv_btnmatrix_get_one_checked() 判断按钮互斥是否开启

二、例程

c 复制代码
// 按键矩阵的事件回调函数
static void btnmatrix_event_callback(lv_event_t * event)
{
    if (event == NULL)
    {
        printf("[%s:%d] event is NULL\n", __FUNCTION__, __LINE__);
        return ;
    }

    lv_event_code_t code = lv_event_get_code(event); // 获取当前event的code
    lv_obj_t * obj = lv_event_get_target(event);     // 获取当前事件的触发对象

    if (code == LV_EVENT_DRAW_PART_BEGIN) // 开始绘制一个区域的事件,这个事件的参数是lv_obj_draw_part_dsc_t *
    {
        lv_obj_draw_part_dsc_t * dsc = (lv_obj_draw_part_dsc_t *)lv_event_get_param(event);
        if (dsc != NULL)
        {
            switch (dsc->id)
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                case 10:
                case 11:
                    {
                        if (lv_btnmatrix_get_selected_btn(obj) == dsc->id)
                        {
                            if (dsc->rect_dsc != NULL)
                            {
                                // 设置目标绘制区域的背景颜色
                                dsc->rect_dsc->bg_color = lv_color_hex(0xFF6008); // 橙色
                            }
                        }
                        else
                        {
                            if (dsc->rect_dsc != NULL)
                            {
                                dsc->rect_dsc->bg_color = lv_color_hex(0xF98E2D);
                            }
                        }

                        if (dsc->rect_dsc != NULL)
                        {
                            dsc->rect_dsc->radius = 5; // 设置目标绘制区域的圆角
                            dsc->rect_dsc->border_width = 0; // 设置目标绘制区域的边框宽度
                            dsc->rect_dsc->shadow_ofs_x = 0; // 在X方向的像素上设置阴影的偏移量
                            dsc->rect_dsc->shadow_ofs_y = 0; // 在Y方向的像素上设置阴影的偏移量
                         }

                         if (dsc->label_dsc != NULL)
                         {
                            dsc->label_dsc->color = lv_color_hex(0xFFFFFF);
                         }
                    }
                    break;

                default:
                    break;
            }
        }
    }
    else if(code == LV_EVENT_VALUE_CHANGED) // 当一个按钮被按下、释放或长按时
    {
        lv_obj_t * text_area = (lv_obj_t *)lv_event_get_user_data(event); // 获取事件的user_data
        uint16_t btn_id = lv_btnmatrix_get_selected_btn(obj);             // 获取当前选中的按键的id
        const char * txt = lv_btnmatrix_get_btn_text(obj, btn_id);        // 获取当前按键的文本

        if (txt != NULL)
        {
            if (strcmp(txt, LV_SYMBOL_BACKSPACE) == 0)
            {
                if (text_area != NULL)
                {
                    lv_textarea_del_char(text_area); // 删除文本框的字符
                }
            }
            else
            {
                if (text_area != NULL)
                {
                    lv_textarea_add_text(text_area, txt); // 文本框追加字符
                }
            }
        }
    }
}


void my_gui()
{
    static const char * btnm_map[] = {"1", "2", "3", "\n",
                                       "4", "5", "6", "\n",
                                       "7", "8", "9", "\n",
                                       ".", "0", LV_SYMBOL_BACKSPACE, ""};

    lv_obj_t * obj_text_area = lv_textarea_create(lv_scr_act()); // 创建文本框控件
    if (obj_text_area == NULL)
    {
        printf("[%s:%d] obj_text_area is NULL\n", __FUNCTION__, __LINE__);
        return ;
    }

    lv_textarea_set_one_line(obj_text_area, true);        // 将文本区域配置为一行
    lv_textarea_set_password_mode(obj_text_area, true);   // 将文本区域配置为密码模式
    lv_textarea_set_max_length(obj_text_area, 15);        // 设置文本区域可输入的字符长度最大值
    lv_obj_add_state(obj_text_area, LV_STATE_FOCUSED);    // 显示光标
    lv_obj_set_style_radius(obj_text_area, 5, 0);         // 设置样式的圆角弧度
    lv_obj_set_style_border_width(obj_text_area, 1, 0);   //设置边框宽度
    lv_obj_set_size(obj_text_area, 255, 40);              // 设置对象大小
    lv_obj_align(obj_text_area, LV_ALIGN_TOP_MID, 0, 50);

    lv_obj_t * obj_btnm = lv_btnmatrix_create(lv_scr_act()); // 创建一个按钮矩阵对象
    if (obj_btnm == NULL)
    {
        printf("[%s:%d] obj_btnm is NULL\n", __FUNCTION__, __LINE__);
        return ;
    }

    lv_btnmatrix_set_one_checked(obj_btnm, true);  // 启用"一次检查"功能,允许一次只检查一个按钮。
    lv_obj_set_size(obj_btnm, 260, 245);           // 设置控件大小
    lv_obj_align(obj_btnm, LV_ALIGN_CENTER, 0, 0);
    lv_obj_clear_flag(obj_btnm, LV_OBJ_FLAG_CLICK_FOCUSABLE); // 按钮按下的是时候焦点才聚集到该控件,确保按钮按下后焦点聚集到文本框
    lv_btnmatrix_set_map(obj_btnm, btnm_map);                 // 给按钮矩阵添加键盘映射

    int i = 0;
    for (i = 0; i < 12; i++)
    {
        lv_btnmatrix_set_btn_ctrl(obj_btnm, i, LV_BTNMATRIX_CTRL_NO_REPEAT); // 长按按钮时禁用重复
    }

    lv_obj_set_style_radius(obj_btnm, 0, 0);                                                       // 设置样式的圆角弧度
    lv_obj_set_style_border_width(obj_btnm, 0, 0);                                                 //设置边框宽度
    lv_obj_set_style_bg_color(obj_btnm, lv_color_hex(0xFFFFFF), 0);                                // 设置背景颜色
    lv_obj_set_style_bg_opa(obj_btnm, LV_OPA_0, 0);                                                // 设置样式背景的不透明度
    lv_obj_set_style_text_font(obj_btnm, &lv_font_montserrat_20, 0);                               //设置字体
    lv_obj_add_event_cb(obj_btnm, btnmatrix_event_callback, LV_EVENT_ALL, (void *)obj_text_area);  // 按钮矩阵添加事件回调函数
}
相关推荐
FreakStudio6 小时前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
python·嵌入式·面向对象·电子diy
weixin_6320776310 小时前
udp聊天室
udp·网络编程·嵌入式·编程·聊天室
fanged2 天前
Linux下的ADSP(TODO)
嵌入式
winddevil2 天前
[rCore学习笔记 027]地址空间
rust·嵌入式·rcore
宇努力学习3 天前
C语言编译原理
c语言·开发语言·嵌入式
玄奕子4 天前
使用vscode上传git远程仓库流程(Gitee)
vscode·gitee·嵌入式·git仓库
—你的鼬先生4 天前
基于树莓派ubuntu20.04的ros-noetic小车
python·嵌入式·ros·树莓派项目
倒霉熊dd5 天前
Cortex-M3架构学习:异常
学习·嵌入式·cortex-m3架构
玄奕子5 天前
GPT对话知识库——串口通信的数据的组成?起始位是高电平还是低电平?如何用代码在 FreeRTOS 中实现串口通信吗?如何处理串口通信中的数据帧校验吗?
stm32·gpt·嵌入式·串口通信·串口数据
正点原子5 天前
[XILINX] 正点原子ZYNQ7015开发板!ZYNQ 7000系列、双核ARM、PCIe2.0、SFPX2,性能强悍,资料丰富!
嵌入式