Is there a widget similar to ListView in this wonderful library? Currently, I’m using a table, but it seems it doesn’t directly support row selection(but cell selection).
Please help
I don’t understand. What do you mean by listview? Table has cell selection which you could just use to select an entire row by reading some of the parameters returned on the VALUE_CHANGED callback that it has.
@Tinus
Thank you for your reply.
First and foremost, I should add that my input device is a keypad, not a touch screen. By listView widget, I mean that in initialization, if any row data is inserted, one row is selected; otherwise, nothing happens; only the widget is created. Then, if the up or down key is pressed and passed to the widget, if it is not at the most extreme, the entire row will be unselected, and the up or down row will be highlighted to show selection. This is only to show records, and the table elements are not to be modified.
Hmm that makes this a bit more difficult but not entirely impossible.
I have no idea how keypad drivers work, is it possible to determine whether up or down has been pressed in a callback? You will have to make a specific draw event callback for the functionality that you want. I don’t have the time now but I may be able to create an example for you. You will basically have to keep track of a “selected index” for your table and in a custom draw callback function, if the row to draw matches the index, you change the background color for that cell.
See this example in the documentation for setting a custom draw callback and changing a cell background color: Table (lv_table) — LVGL documentation
What I want is exactly like this, except that I wish to highlight the entire row, not just the selected cell.
Yes, that is already what the example above does. Every cell in row 0 is light blue. Each cell on a row will take on that color, hence the entire row is light blue.
That one doesn’t change the color of the selected cell, What I want is that the selected row remain highlighted until there is a next input from the keypad.
Yes, as I said you will have to do some trickery yourself for this.
You do not use the selected cell, instead use the keypad input to determine which cell to highlight (index up or down). Is this possible?
What I need is to make the background change.
second example suggest to use this function
static void change_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
uint32_t col;
uint32_t row;
lv_table_get_selected_cell(obj, &row, &col);
bool chk = lv_table_has_cell_ctrl(obj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
if(chk) lv_table_clear_cell_ctrl(obj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
else lv_table_add_cell_ctrl(obj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
}
and latter to find which one has control suggest this line.
if(base_dsc->part == LV_PART_ITEMS && lv_draw_task_get_type(draw_task) == LV_DRAW_TASK_TYPE_FILL) {
/*Draw the background*/
bool chk = lv_table_has_cell_ctrl(obj, base_dsc->id1, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
so the check variable finds which cell is selected. now I don’t know how to make it steady. when the cell is clicked, its background is going to become gray and on release its going to become white again. what I want is that I don’t want the cell or row to become white again, but remains selected and have gray background. Its background should become white when other cell is selected.
Simply put the row index of the last selected cell in a global variable. In your draw callback, use that index to draw the background of every cell in that row a certain color.
Also remove the “pressed style” (which makes cells briefly turn gray when pressed):
/*Don't make the cell pressed, we will draw something different in the event*/
lv_obj_remove_style(table, NULL, LV_PART_ITEMS | LV_STATE_PRESSED);
Thank you for this mention
This is what I don’t know how to do. I mean I don’t know how to change the background rather drawing a rectangle.
I will send you an example sometime this week.
@Tinus
Thank you
Based on your advice and examples, I have manipulated example codes and now this code seems helpful
#include "../../lv_examples.h"
#if LV_USE_TABLE && LV_BUILD_EXAMPLES
static void draw_event_cb(lv_event_t * e)
{
lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
lv_draw_dsc_base_t * base_dsc = draw_task->draw_dsc;
lv_obj_t * obj = lv_event_get_target(e);
/*If the cells are drawn...*/
if(base_dsc->part == LV_PART_ITEMS) {
uint32_t row = base_dsc->id1;
uint32_t col = base_dsc->id2;
/*Make the texts in the first cell center aligned*/
if(row == 0) {
lv_draw_label_dsc_t * label_draw_dsc = lv_draw_task_get_label_dsc(draw_task);
if(label_draw_dsc) {
label_draw_dsc->align = LV_TEXT_ALIGN_CENTER;
}
lv_draw_fill_dsc_t * fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
if(fill_draw_dsc) {
fill_draw_dsc->color = lv_color_mix(lv_palette_main(LV_PALETTE_BLUE), fill_draw_dsc->color, LV_OPA_20);
fill_draw_dsc->opa = LV_OPA_COVER;
}
}
bool chk = lv_table_has_cell_ctrl(obj, base_dsc->id1, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
/*Make every 2nd row grayish*/
if((row != 0 && row % 2) == 0) {
lv_draw_fill_dsc_t * fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
if(fill_draw_dsc) {
fill_draw_dsc->color = lv_color_mix(lv_palette_main(LV_PALETTE_GREY), fill_draw_dsc->color, LV_OPA_10);
fill_draw_dsc->opa = LV_OPA_COVER;
}
}
if (chk == true&& draw_task->type == LV_DRAW_TASK_TYPE_FILL)
{
lv_draw_fill_dsc_t * fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
fill_draw_dsc->color = lv_color_make(255,0,0);
fill_draw_dsc->opa = LV_OPA_COVER;
}
}
}
static void change_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
uint32_t col;
uint32_t row;
static uint8_t lastRow = 0;
lv_table_get_selected_cell(obj, &row, &col);
if (lastRow != row)
{
lv_table_clear_cell_ctrl(obj, lastRow, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
bool chk = lv_table_has_cell_ctrl(obj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
if(chk) lv_table_clear_cell_ctrl(obj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
else lv_table_add_cell_ctrl(obj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1);
lastRow = row;
}
}
void lv_example_table_1(void)
{
lv_obj_t * table = lv_table_create(lv_screen_active());
/*Fill the first column*/
lv_table_set_cell_value(table, 0, 0, "Name");
lv_table_set_cell_value(table, 1, 0, "Apple");
lv_table_set_cell_value(table, 2, 0, "Banana");
lv_table_set_cell_value(table, 3, 0, "Lemon");
lv_table_set_cell_value(table, 4, 0, "Grape");
lv_table_set_cell_value(table, 5, 0, "Melon");
lv_table_set_cell_value(table, 6, 0, "Peach");
lv_table_set_cell_value(table, 7, 0, "Nuts");
/*Fill the second column*/
lv_table_set_cell_value(table, 0, 1, "Price");
lv_table_set_cell_value(table, 1, 1, "$7");
lv_table_set_cell_value(table, 2, 1, "$4");
lv_table_set_cell_value(table, 3, 1, "$6");
lv_table_set_cell_value(table, 4, 1, "$2");
lv_table_set_cell_value(table, 5, 1, "$5");
lv_table_set_cell_value(table, 6, 1, "$1");
lv_table_set_cell_value(table, 7, 1, "$9");
/*Set a smaller height to the table. It'll make it scrollable*/
lv_obj_set_height(table, 200);
lv_obj_center(table);
lv_obj_remove_style(table, NULL, LV_PART_ITEMS | LV_STATE_PRESSED);
/*Add an event callback to to apply some custom drawing*/
lv_obj_add_event_cb(table, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_event_cb(table, change_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_add_flag(table, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
}
#endif
I thought I was working on version 8.4 but the code I posted is based on v9.0.
This my implementation on V8.4 but I appreciate your quotes
#include "../../lv_examples.h"
#include "log.h"
#if LV_USE_TABLE && LV_BUILD_EXAMPLES
static uint8_t selRow = 0;
static void draw_part_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
/*If the cells are drawn...*/
if(dsc->part == LV_PART_ITEMS)
{
uint32_t row = dsc->id / lv_table_get_col_cnt(obj);
uint32_t col = dsc->id - row * lv_table_get_col_cnt(obj);
/*Make the texts in the first cell center aligned*/
if(row == 0) {
dsc->label_dsc->align = LV_TEXT_ALIGN_CENTER;
dsc->rect_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_BLUE), dsc->rect_dsc->bg_color, LV_OPA_20);
dsc->rect_dsc->bg_opa = LV_OPA_COVER;
}
/*MAke every 2nd row grayish*/
if((row != 0 && row % 2) == 0) {
dsc->rect_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_GREY), dsc->rect_dsc->bg_color, LV_OPA_10);
dsc->rect_dsc->bg_opa = LV_OPA_COVER;
}
if (selRow == row & selRow != 0)
{
dsc->rect_dsc->bg_color = lv_color_make(255,0,0);
dsc->rect_dsc->bg_opa = LV_OPA_COVER;
}
}
}
static void change_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
uint16_t col;
uint16_t row;
lv_table_get_selected_cell(obj, &row, &col);
if (selRow != row & row != 0)
{
selRow = row;
}
}
void lv_example_table_1(void)
{
lv_obj_t * table = lv_table_create(lv_scr_act());
/*Fill the first column*/
lv_table_set_cell_value(table, 0, 0, "Name");
lv_table_set_cell_value(table, 1, 0, "Apple");
lv_table_set_cell_value(table, 2, 0, "Banana");
lv_table_set_cell_value(table, 3, 0, "Lemon");
lv_table_set_cell_value(table, 4, 0, "Grape");
lv_table_set_cell_value(table, 5, 0, "Melon");
lv_table_set_cell_value(table, 6, 0, "Peach");
lv_table_set_cell_value(table, 7, 0, "Nuts");
/*Fill the second column*/
lv_table_set_cell_value(table, 0, 1, "Price");
lv_table_set_cell_value(table, 1, 1, "$7");
lv_table_set_cell_value(table, 2, 1, "$4");
lv_table_set_cell_value(table, 3, 1, "$6");
lv_table_set_cell_value(table, 4, 1, "$2");
lv_table_set_cell_value(table, 5, 1, "$5");
lv_table_set_cell_value(table, 6, 1, "$1");
lv_table_set_cell_value(table, 7, 1, "$9");
/*Set a smaller height to the table. It'll make it scrollable*/
lv_obj_set_height(table, 200);
lv_obj_center(table);
lv_obj_remove_style(table, NULL, LV_PART_ITEMS | LV_STATE_PRESSED);
/*Add an event callback to to apply some custom drawing*/
lv_obj_add_event_cb(table, draw_part_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
lv_obj_add_event_cb(table, change_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
}
#endif
Maybe we can make it a feature of the table. Now we have
void lv_table_set_selected_cell(lv_obj_t * obj, uint16_t row, uint16_t col);
Let’s say we create a define like:
#define LV_TABLE_COLUMN_ALL 0xffff
and
lv_table_set_selected_cell(table, 2, LV_TABLE_COLUMN_ALL);
It will instruct LVGL to recolor all the columns.
What do you think?
@kisvegabor In the context of listview, if list has at least one element, it should show selected one otherwise nothing. (First difference with current implementation of table)
Then selected row should have static color, rather only showing different color on press and release only, by which I mean it should hold the background color.
Got it. I think statically selecting a cell is a good table feature too. If you are open to send a PR we can discuss the details on GitHub
I was away for some time, sorry for late reply
Should I add a new example file for pr?
Yes, that would be amazing!