Button matrix(矩阵按钮) (lv_buttonmatrix)
Overview(概述)
显示原文
The Button Matrix object is a lightweight way to display multiple buttons in rows and columns. Lightweight because the buttons are not actually created but just virtually drawn on the fly. This way, one button use only eight extra bytes of memory instead of the ~100-150 bytes a normal Button object plus the 100 or so bytes for the Label object.
The Button matrix is added to the default group (if one is set). Besides the Button matrix is an editable object to allow selecting and clicking the buttons with encoder navigation too.
矩阵按钮(lv_btnmatrix)控件是一种在行和列中显示多个按钮的轻量级实现方式。按钮不是实际创建出来的,而是实时绘制出来的,所以轻量级,因为这样一个按钮仅使用 8 个字节的内存,而不是普通 Button 控件那样:~100-150 字节再加上 Label 控件的内存占用。
矩阵按钮添加到默认组(如果之前已设置了组)。此外,矩阵按钮是一个可编辑的对象,可以通过编码器导航选择和单击按钮。
Parts and Styles(部分和样式)
显示原文
LV_PART_MAIN
The background of the button matrix, uses the typical background style properties.pad_row
andpad_column
sets the space between the buttons.LV_PART_ITEMS
The buttons all use the text and typical background style properties except translations and transformations.
LV_PART_MAIN
矩阵按钮的背景,使用所有控件默认都有的典型的背景样式属性。可通过pad_row
和pad_column
设置按钮之间的空间。LV_PART_ITEMS
除了转变之外,按钮都使用文本和典型的背景样式属性。
Usage(用法)
Button's text(按钮的文字)
显示原文
There is a text on each button. To specify them a descriptor string
array, called map, needs to be used. The map can be set with
lv_buttonmatrix_set_map(buttonm, my_map). The declaration of a map should
look like const char * map[] = {"button1", "button2", "button3", NULL}. Note
that the last element has to be either NULL
or an empty string
(""
)!
Use "\n"
in the map to insert a line break. E.g.
{"button1", "button2", "\n", "button3", ""}
. Each line's buttons have their
width calculated automatically. So in the example the first row will
have 2 buttons each with 50% width and a second row with 1 button having
100% width.
每个按钮上都可以有文字。要指定按钮的文字,需要使用称为 map 的描述符按钮布局的字符串数组。 map 可以使用 lv_buttonmatrix_set_map(buttonm, my_map) 接口设置。 map 的格式: const char * map[] = {"button1", "button2", "button3", NULL}。 请注意,map 数组的最后一个元素必须是 NULL
或空字符串(""
)!
在 map 中使用 "\n"
插入 换行符。 例如。 {"button1", "button2", "\n", "button3", ""}
。 每行按钮的宽度都会自动计算平均分配(默认)。 因此,在上面的示例中,第一行将有 2 个按钮,每个按钮的宽度为 50%,第二行将有 1 个按钮的宽度为 100%。
Control buttons(控制按钮)
显示原文
The buttons' width can be set relative to the other button in the same row with lv_buttonmatrix_set_button_width(buttonm, button_id, width) E.g. in a line with two buttons: buttonA, width = 1 and buttonB, width = 2, buttonA will have 33 % width and buttonB will have 66 % width. It's similar to how the "flex-grow" property works in CSS. The width must be in the [1..15] range and the default width is 1.
In addition to the width, each button can be customized with the following parameters:
LV_BUTTONMATRIX_CTRL_HIDDEN
: Makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable)LV_BUTTONMATRIX_CTRL_NO_REPEAT
: Disable repeating when the button is long pressedLV_BUTTONMATRIX_CTRL_DISABLED
: Makes a button disabled LikeLV_STATE_DISABLED
on normal objectsLV_BUTTONMATRIX_CTRL_CHECKABLE
: Enable toggling of a button. I.e.LV_STATE_CHECKED
will be added/removed as the button is clickedLV_BUTTONMATRIX_CTRL_CHECKED
: Make the button checked. It will use theLV_STATE_CHECHKED
styles.LV_BUTTONMATRIX_CTRL_CLICK_TRIG
: Enabled: send LV_EVENT_VALUE_CHANGE on CLICK, Disabled: sendLV_EVENT_VALUE_CHANGE
on PRESSLV_BUTTONMATRIX_CTRL_POPOVER
: Show the button label in a popover when pressing this keyLV_BUTTONMATRIX_CTRL_CUSTOM_1
: Custom free to use flagLV_BUTTONMATRIX_CTRL_CUSTOM_2
: Custom free to use flag
By default, all flags are disabled.
To set or clear a button's control attribute, use
lv_buttonmatrix_set_button_ctrl(buttonm, button_id, LV_BUTTONMATRIX_CTRL_...) and
lv_buttonmatrix_clear_button_ctrl(buttonm, button_id, LV_BUTTONMATRIX_CTRL_...)
respectively. More LV_BUTTONMATRIX_CTRL_...
values can be OR-ed
To set/clear the same control attribute for all buttons of a button matrix, use lv_buttonmatrix_set_button_ctrl_all(buttonm, LV_BUTTONMATRIX_CTRL_...) and lv_buttonmatrix_clear_button_ctrl_all(buttonm, LV_BUTTONMATRIX_CTRL_...).
The set a control map for a button matrix (similarly to the map for the
text), use lv_buttonmatrix_set_ctrl_map(buttonm, ctrl_map). An element of
ctrl_map
should look like
ctrl_map[0] = width | LV_BUTTONMATRIX_CTRL_NO_REPEAT | LV_BUTTONMATRIX_CTRL_CHECHKABLE.
The number of elements should be equal to the number of buttons
(excluding newlines characters).
可以使用 lv_buttonmatrix_set_button_width(buttonm, button_id, width) 接口设置相对于同一行中的另一个按钮的宽度。 例如。在一行中有两个按钮这样设置:btnA, width = 1 和 btnB, width = 2,这样btnA 将有 33% 的宽度,btnB 将有 66% 的宽度。 它类似于 "flex-grow" 属性在 CSS 中的工作方式。 宽度必须在 [1..15] 范围内,默认宽度为 1。
除了宽度之外,每个按钮还可以使用以下参数进行自定义:
LV_BUTTONMATRIX_CTRL_HIDDEN
: 隐藏按钮(隐藏的按钮仍然占用布局中的空间,它们只是不可见或不可点击)LV_BUTTONMATRIX_CTRL_NO_REPEAT
: 长按按钮时禁用重复LV_BUTTONMATRIX_CTRL_DISABLED
: 使按钮被禁用,就像普通对象上的 LV_STATE_DISABLEDLV_BUTTONMATRIX_CTRL_CHECKABLE
: 启用按钮切换。也就是 LV_STATE_CHECHED 将在按钮被点击时添加/删除LV_BUTTONMATRIX_CTRL_CHECKED
: 检查按钮。它将使用 LV_STATE_CHECHKED 的样式。LV_BUTTONMATRIX_CTRL_CLICK_TRIG
: 启用:在点击时发送 LV_EVENT_VALUE_CHANGE ;禁用:在按下时发送 LV_EVENT_VALUE_CHANGELV_BUTTONMATRIX_CTRL_POPOVER
: 按下此键时在弹出框中显示按钮标签LV_BUTTONMATRIX_CTRL_CUSTOM_1
: 可自定义使用的标志LV_BUTTONMATRIX_CTRL_CUSTOM_2
: 可自定义使用的标志
默认情况下,所有标志都被禁用。
要设置或清除按钮的控制属性,请使用 lv_buttonmatrix_set_button_ctrl(buttonm, button_id, LV_BUTTONMATRIX_CTRL_...) 和 lv_buttonmatrix_clear_button_ctrl(buttonm, button_id, LV_BUTTONMATRIX_CTRL_...) 。 更多 LV_BUTTONMATRIX_CTRL_...
值可以被 OR-ed
要为矩阵按钮的所有按钮设置/清除相同的控制属性,请使用 lv_buttonmatrix_set_button_ctrl_all(buttonm, LV_BUTTONMATRIX_CTRL_...) 和 lv_buttonmatrix_clear_button_ctrl_all(buttonm, LV_BUTTONMATRIX_CTRL_...)。
我们可以写一个数组来一次单独设置多个或者所有的按钮,这有点像一个控制表,这里称其为 ctrl_map
,我们可以使用 lv_buttonmatrix_set_ctrl_map(buttonm, ctrl_map) 将控制表添加到矩阵按钮中。 ctrl_map
中的元素的格式 ctrl_map[0] = width | LV_BUTTONMATRIX_CTRL_NO_REPEAT | LV_BUTTONMATRIX_CTRL_CHECHKABLE,也就是我们可以添加多个属性。 元素的数量应该等于(可以小于,但是不应该超出)按钮的数量(不包括换行符)。
One check(一次检查)
显示原文
The "One check" feature can be enabled with lv_buttonmatrix_set_one_checked(buttonm, true) to allow only one button to be checked at a time.
可以使用 lv_buttonmatrix_set_one_checked(buttonm, true) 启用 “一次检查” 功能,这样一次只能检查一个按钮(我们就能知道最后点击的是哪个按钮)。
Events(事件)
显示原文
LV_EVENT_VALUE_CHANGED
: Sent when a button is pressed/released or repeated after long press. The event parameter is set to the ID of the pressed/released button.
See the events of the Base object too.
lv_buttonmatrix_get_selected_button(buttonm) returns the index of the most
recently released or focused button or LV_BUTTONMATRIX_BUTTON_NONE
if no
such button.
lv_buttonmatrix_get_button_text(buttonm, button_id) returns a pointer to the
text of button_id
th button.
Learn more about Events(事件).
LV_EVENT_VALUE_CHANGED
: 按下/释放按钮或长按时发送。事件参数设置为按下/释放按钮的ID。
另请参阅 基本对象 的事件。
lv_buttonmatrix_get_selected_button(buttonm) 返回最近被释放或聚焦按钮的索引。如果没有这样的按钮,则返回 LV_BUTTONMATRIX_BUTTON_NONE
。
lv_buttonmatrix_get_button_text(buttonm, button_id) 返回指向文本 button_id
的按钮。
详细了解更多 Events(事件)。
Keys(按键)
显示原文
LV_KEY_RIGHT/UP/LEFT/RIGHT
To navigate among the buttons to select oneLV_KEY_ENTER
To press/release the selected button
Note that long pressing the button matrix with an encoder can mean to enter/leave edit mode and simply long pressing a button to make it repeat as well. To avoid this contradiction it's suggested to add lv_buttonmatrix_set_button_ctrl_all(buttonm, LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_NO_REPEAT) to the button matrix if used with encoder. This way, the pressed button repeat feature is disabled and on leaving edit mode the selected button won't be activated.
Learn more about Keys(按键).
LV_KEY_RIGHT/UP/LEFT/RIGHT
在矩阵按钮的按钮之间导航来选中不同的按钮。LV_KEY_ENTER
按下/释放所选按钮。
请注意,长按编码器的矩阵按钮可能意味着进入/退出编辑模式,只需长按一个按钮即可以重复。为了避免这种矛盾,建议添加 lv_buttonmatrix_set_button_ctrl_all(buttonm, LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_NO_REPEAT) 到矩阵按钮(如果与编码器一起使用)。这样,按下的按钮重复功能被禁用,并且在离开编辑模式时,选择按钮不会被激活。
了解有关 Keys(按键) 的更多信息。
Example
Simple Button matrix
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_BUTTONMATRIX && LV_BUILD_EXAMPLES
static void event_handler(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
uint32_t id = lv_buttonmatrix_get_selected_button(obj);
const char * txt = lv_buttonmatrix_get_button_text(obj, id);
LV_UNUSED(txt);
LV_LOG_USER("%s was pressed\n", txt);
}
}
static const char * btnm_map[] = {"1", "2", "3", "4", "5", "\n",
"6", "7", "8", "9", "0", "\n",
"Action1", "Action2", ""
};
void lv_example_buttonmatrix_1(void)
{
lv_obj_t * btnm1 = lv_buttonmatrix_create(lv_screen_active());
lv_buttonmatrix_set_map(btnm1, btnm_map);
lv_buttonmatrix_set_button_width(btnm1, 10, 2); /*Make "Action1" twice as wide as "Action2"*/
lv_buttonmatrix_set_button_ctrl(btnm1, 10, LV_BUTTONMATRIX_CTRL_CHECKABLE);
lv_buttonmatrix_set_button_ctrl(btnm1, 11, LV_BUTTONMATRIX_CTRL_CHECKED);
lv_obj_align(btnm1, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(btnm1, event_handler, LV_EVENT_ALL, NULL);
}
#endif
Custom buttons
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_BUTTONMATRIX && LV_BUILD_EXAMPLES
static void event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = lv_draw_task_get_draw_dsc(draw_task);
/*When the button matrix draws the buttons...*/
if(base_dsc->part == LV_PART_ITEMS) {
bool pressed = false;
if(lv_buttonmatrix_get_selected_button(obj) == base_dsc->id1 && lv_obj_has_state(obj, LV_STATE_PRESSED)) {
pressed = true;
}
/*Change the draw descriptor of the 2nd button*/
if(base_dsc->id1 == 1) {
lv_draw_fill_dsc_t * fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
if(fill_draw_dsc) {
fill_draw_dsc->radius = 0;
if(pressed) fill_draw_dsc->color = lv_palette_darken(LV_PALETTE_BLUE, 3);
else fill_draw_dsc->color = lv_palette_main(LV_PALETTE_BLUE);
}
lv_draw_box_shadow_dsc_t * box_shadow_draw_dsc = lv_draw_task_get_box_shadow_dsc(draw_task);
if(box_shadow_draw_dsc) {
box_shadow_draw_dsc->width = 6;
box_shadow_draw_dsc->ofs_x = 3;
box_shadow_draw_dsc->ofs_y = 3;
}
lv_draw_label_dsc_t * label_draw_dsc = lv_draw_task_get_label_dsc(draw_task);
if(label_draw_dsc) {
label_draw_dsc->color = lv_color_white();
}
}
/*Change the draw descriptor of the 3rd button*/
else if(base_dsc->id1 == 2) {
lv_draw_fill_dsc_t * fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
if(fill_draw_dsc) {
fill_draw_dsc->radius = LV_RADIUS_CIRCLE;
if(pressed) fill_draw_dsc->color = lv_palette_darken(LV_PALETTE_RED, 3);
else fill_draw_dsc->color = lv_palette_main(LV_PALETTE_RED);
}
}
else if(base_dsc->id1 == 3) {
lv_draw_label_dsc_t * label_draw_dsc = lv_draw_task_get_label_dsc(draw_task);
if(label_draw_dsc) {
label_draw_dsc->opa = 0;
}
if(lv_draw_task_get_type(draw_task) == LV_DRAW_TASK_TYPE_FILL) {
LV_IMAGE_DECLARE(img_star);
lv_image_header_t header;
lv_result_t res = lv_image_decoder_get_info(&img_star, &header);
if(res != LV_RESULT_OK) return;
lv_area_t a;
a.x1 = 0;
a.x2 = header.w - 1;
a.y1 = 0;
a.y2 = header.h - 1;
lv_area_t draw_task_area;
lv_draw_task_get_area(draw_task, &draw_task_area);
lv_area_align(&draw_task_area, &a, LV_ALIGN_CENTER, 0, 0);
lv_draw_image_dsc_t img_draw_dsc;
lv_draw_image_dsc_init(&img_draw_dsc);
img_draw_dsc.src = &img_star;
img_draw_dsc.recolor = lv_color_black();
if(pressed) img_draw_dsc.recolor_opa = LV_OPA_30;
lv_draw_image(base_dsc->layer, &img_draw_dsc, &a);
}
}
}
}
/**
* Add custom drawer to the button matrix to customize buttons one by one
*/
void lv_example_buttonmatrix_2(void)
{
lv_obj_t * btnm = lv_buttonmatrix_create(lv_screen_active());
lv_obj_add_event_cb(btnm, event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_flag(btnm, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
lv_obj_center(btnm);
}
#endif
Pagination
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_BUTTONMATRIX && LV_BUILD_EXAMPLES
static void event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
uint32_t id = lv_buttonmatrix_get_selected_button(obj);
bool prev = id == 0;
bool next = id == 6;
if(prev || next) {
/*Find the checked button*/
uint32_t i;
for(i = 1; i < 7; i++) {
if(lv_buttonmatrix_has_button_ctrl(obj, i, LV_BUTTONMATRIX_CTRL_CHECKED)) break;
}
if(prev && i > 1) i--;
else if(next && i < 5) i++;
lv_buttonmatrix_set_button_ctrl(obj, i, LV_BUTTONMATRIX_CTRL_CHECKED);
}
}
/**
* Make a button group (pagination)
*/
void lv_example_buttonmatrix_3(void)
{
static lv_style_t style_bg;
lv_style_init(&style_bg);
lv_style_set_pad_all(&style_bg, 0);
lv_style_set_pad_gap(&style_bg, 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);
lv_style_set_border_opa(&style_btn, LV_OPA_50);
lv_style_set_border_color(&style_btn, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_border_side(&style_btn, LV_BORDER_SIDE_INTERNAL);
lv_style_set_radius(&style_btn, 0);
static const char * map[] = {LV_SYMBOL_LEFT, "1", "2", "3", "4", "5", LV_SYMBOL_RIGHT, ""};
lv_obj_t * btnm = lv_buttonmatrix_create(lv_screen_active());
lv_buttonmatrix_set_map(btnm, map);
lv_obj_add_style(btnm, &style_bg, 0);
lv_obj_add_style(btnm, &style_btn, LV_PART_ITEMS);
lv_obj_add_event_cb(btnm, event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_set_size(btnm, 225, 35);
/*Allow selecting on one number at time*/
lv_buttonmatrix_set_button_ctrl_all(btnm, LV_BUTTONMATRIX_CTRL_CHECKABLE);
lv_buttonmatrix_clear_button_ctrl(btnm, 0, LV_BUTTONMATRIX_CTRL_CHECKABLE);
lv_buttonmatrix_clear_button_ctrl(btnm, 6, LV_BUTTONMATRIX_CTRL_CHECKABLE);
lv_buttonmatrix_set_one_checked(btnm, true);
lv_buttonmatrix_set_button_ctrl(btnm, 1, LV_BUTTONMATRIX_CTRL_CHECKED);
lv_obj_center(btnm);
}
#endif