Add objects dynamic to a page

Description

For a home automation system I am developing I am looking for a nice way to dynamically add “components” to my HMI.
Note, the “building” of the components only runs once at start based on a config file. (So before lv_task_handler() is called)

What MCU/Processor/Board and compiler are you using?

The LVGL Simulator for visual studio

What LVGL version are you using?

V8.3.0 @Update ROADMAP.rst · lvgl/lvgl@ed681f9 · GitHub

What do you want to achieve?

Something that looks like the screenshots in this topic. How do you remove the padding of a page on a tabview page?

What have you tried so far?

Added the tabview widget with a bar on the 1st tab and now I am trying to add multiple buttons on a grid. However now I get everything on both pages.

Code to reproduce

lv_obj_t* AddClimate(lv_obj_t* parent)
{
    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(parent);
    lv_obj_add_style(bar, &style_indic, LV_PART_INDICATOR);
    lv_obj_set_size(bar, 20, 200);
    lv_obj_center(bar);
    lv_bar_set_range(bar, -20, 40);

    return NULL;
}

static void LightEventHandler(lv_event_t* e)
{
    int* index = (int*)lv_event_get_user_data(e);

    LV_LOG_USER("Light Toggled %d", *index);
}

lv_obj_t* AddLight(lv_obj_t* parent, const char* name, int* index)
{
    lv_obj_t* button = lv_btn_create(parent);
    lv_obj_add_event(button, LightEventHandler, LV_EVENT_VALUE_CHANGED, index);
    lv_obj_add_flag(button, LV_OBJ_FLAG_CHECKABLE);
    lv_obj_set_height(button, LV_SIZE_CONTENT);

    lv_obj_center(button);

    lv_obj_t* label = lv_label_create(button);
    lv_label_set_text(label, name);
    lv_obj_center(label);

    return button;
}

void CreateScreen1(void)
{
    /*Create a Tab view object*/
    lv_obj_t* tabView = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 50);
    lv_obj_t* tabContent = lv_tabview_get_content(tabView);

    lv_obj_clear_flag(tabContent, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_layout(tabContent, LV_LAYOUT_GRID);

    static lv_coord_t column_dsc[] = { 100, 100, LV_GRID_TEMPLATE_LAST };   /*2 columns with 100 and 400 ps width*/
    static lv_coord_t row_dsc[] = { 100, 100, 100, LV_GRID_TEMPLATE_LAST }; /*3 100 px tall rows*/

    //Add the climate group
    lv_obj_t* climateTab = lv_tabview_add_tab(tabView, "Climate");
    lv_obj_t* climate = AddClimate(climateTab);

    
    lv_obj_t* lightTab = lv_tabview_add_tab(tabView, "Light");

    static int mainIndex = 1;
    lv_obj_t* mainLight = AddLight(lightTab, "Main", &mainIndex);
    lv_obj_set_grid_cell(mainLight, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_STRETCH, 0, 1);

    static int secondIndex = 2;
    lv_obj_t* secondLight = AddLight(lightTab, "Second", &secondIndex);
    lv_obj_set_grid_cell(secondLight, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_STRETCH, 1, 1);   
}

Screenshot and/or video

Tab 1:


Tab 2:

Update, I think I was just doing something wrong. This is my working code if someone is looking for a reference.


static void LightEventHandler(lv_event_t* e)
{
    int* index = (int*)lv_event_get_user_data(e);

    lv_obj_t* obj = (lv_obj_t*)lv_event_get_target(e);

    LV_LOG_USER("Light Toggled %d", *index);
    LV_LOG_USER("To State: %s\n", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "On" : "Off");
}

lv_obj_t* AddLightSwitch(lv_obj_t* parent, const char* name, int* index)
{
    static lv_coord_t grid_main_col_dsc[] = { LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST };
    static lv_coord_t grid_main_row_dsc[] = { LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST };

    lv_obj_t* switchPanel = lv_obj_create(parent);
    lv_obj_set_grid_dsc_array(switchPanel, grid_main_col_dsc, grid_main_row_dsc);
    lv_obj_set_width(switchPanel, LV_SIZE_CONTENT);
    lv_obj_set_height(switchPanel, LV_SIZE_CONTENT);

    lv_obj_t* switchLabel = lv_label_create(switchPanel);
    lv_label_set_text(switchLabel, name);
    lv_obj_set_width(switchLabel, LV_SIZE_CONTENT);
    lv_obj_set_height(switchLabel, LV_SIZE_CONTENT);

    lv_obj_t* switchBtn = lv_switch_create(switchPanel);
    lv_obj_add_event(switchBtn, LightEventHandler, LV_EVENT_VALUE_CHANGED, index);
    lv_obj_set_width(switchBtn, 50);
    lv_obj_set_height(switchBtn, 25);

    lv_obj_set_grid_cell(switchLabel, LV_GRID_ALIGN_SPACE_EVENLY, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
    lv_obj_set_grid_cell(switchBtn,   LV_GRID_ALIGN_SPACE_EVENLY, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);

    return switchPanel;
}

void CreateScreen1(void)
{
    /*Create a Tab view object*/
    lv_obj_t* tabView = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 50);
    lv_obj_clear_flag(lv_tabview_get_content(tabView), LV_OBJ_FLAG_SCROLLABLE);
   
    lv_obj_t* lightTab = lv_tabview_add_tab(tabView, "Light");
    
    static lv_coord_t grid_main_col_dsc[] = { LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
    static lv_coord_t grid_main_row_dsc[] = { LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST };
    
    lv_obj_set_grid_dsc_array(lightTab, grid_main_col_dsc, grid_main_row_dsc);

    static int mainIndex = 1;
    lv_obj_t* mainLight = AddLightSwitch(lightTab, "Main", &mainIndex);
    lv_obj_set_grid_cell(mainLight, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_STRETCH, 0, 1);

    static int secondIndex = 2;
    lv_obj_t* secondLight = AddLightSwitch(lightTab, "Second", &secondIndex);
    lv_obj_set_grid_cell(secondLight, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_STRETCH, 0, 1);
}

If you also get stuck, check the “full” example “lv_demo_widgets()”. This helpend me a lot.
@maintainers, would you mind adding more “full” examples? (like the widgets demo).