Set event callback for tabview press

Description

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

ESP32-S3

What LVGL version are you using?

8.3.6

What do you want to achieve?

tabview event callback. I want to know which tab is pressed out of multiple tabs. I want to add some application based on which tab has been pressed.
I have tried to implement similar the one discussed in How to set a new event-callback for tabview - #2 by TridentTD
but it fails while compilation
error: expected expression before '[' token

lv_obj_t* tabview = lv_tabview_create(lv_scr_act(), NULL);

    lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Tab 1");
    lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Tab 2");
    lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Tab 3");

    lv_obj_set_event_cb(tabview, [](lv_obj_t* tabview, lv_event_t event){
      if(event != LV_EVENT_VALUE_CHANGED) return;
      
      lv_tabview_ext_t* ext = (lv_tabview_ext_t*) lv_obj_get_ext_attr(tabview);
      const char* tab_name = ext->tab_name_ptr[lv_tabview_get_tab_act(tabview)];
      
      printf("Current Active Tab : %s\n", tab_name);
    });

What have you tried so far?

created tabview with 5 tabs and tried to create eventcallback similar to button widget. but the callback function is not getting called when any tab is pressed.

lv_obj_add_event_cb(ui_TAB1, ui_event_TAB1, LV_EVENT_ALL, NULL);
lv_obj_add_event_cb(ui_TAB2, ui_event_TAB2, LV_EVENT_ALL, NULL);

void ui_event_TAB1(lv_event_t * e){
  lv_event_code_t event_code = lv_event_get_code(e);
  lv_obj_t * target = lv_event_get_target(e);
  if(event_code == LV_EVENT_VALUE_CHANGED ) {
     debug_print("\ntab1_pressed");
  }
}

void ui_event_TAB2(lv_event_t * e){
  lv_event_code_t event_code = lv_event_get_code(e);
  lv_obj_t * target = lv_event_get_target(e);
  if(event_code == LV_EVENT_VALUE_CHANGED ) {
     debug_print("\ntab2_pressed");
  }
}

Are these ui_TABx objects tabviews or tabs?
If they are tabviews (i.e. created with lv_tabview_create()) then I am not sure why this would not work.

Perhaps instead of LV_EVENT_ALL, could you try LV_EVENT_VALUE_CHANGED?
So:

lv_obj_add_event_cb(ui_TAB1, ui_event_TAB1, LV_EVENT_VALUE_CHANGED, NULL);

Hi Tinus,
Here is how i created 5 ‘ui_TABx’ tabs under ‘ui_TABS’. for these ui_TABx tabs, i want to add event. But it doesn’t work. In lvgl documentations as well there is no such callback event for tabs.
Actually, instead of creating individual widgets (like buttons, arc etc…) in each tab, i want to access to have common widgets for all tabs and access widgets using individual variables defined for each tab. This i want to reduce memory as i need multiple widgets in a tab and creating individual widgets for each tabs would require lots of memory. Hence, I want like which tab has been pressed and then use corresponding variables to access the widgets. I know this is going to be little complicated but i feel its better if somehow i know which tab has been pressed.

    ui_TABS = lv_tabview_create(ui_TABS_root_PANEL, LV_DIR_TOP, 48);
    lv_obj_set_width(ui_TABS, 663);
    lv_obj_set_height(ui_TABS, 48);
    lv_obj_set_x(ui_TABS, 5);
    lv_obj_set_y(ui_TABS, -474);
    lv_obj_set_align(ui_TABS, LV_ALIGN_BOTTOM_LEFT);
    lv_obj_clear_flag(ui_TABS, LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_SCROLL_ELASTIC | LV_OBJ_FLAG_SCROLL_MOMENTUM |
                      LV_OBJ_FLAG_SCROLL_CHAIN);     /// Flags
    lv_obj_set_style_radius(ui_TABS, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(ui_TABS, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ui_TABS, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_color(ui_TABS, lv_color_hex(0x868080), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_opa(ui_TABS, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_width(ui_TABS, 1, LV_PART_MAIN | LV_STATE_DEFAULT);


    ui_TAB1 = lv_tabview_add_tab(ui_TABS, "TAB1");

    ui_TAB2 = lv_tabview_add_tab(ui_TABS, "TAB2");
    lv_obj_clear_flag(ui_TAB2, LV_OBJ_FLAG_SCROLLABLE);      /// Flags

    ui_TAB3 = lv_tabview_add_tab(ui_TABS, "TAB3");

    ui_TAB4 = lv_tabview_add_tab(ui_TABS, "TAB4");
    lv_obj_clear_flag(ui_TAB4, LV_OBJ_FLAG_SCROLLABLE);      /// Flags

    ui_TAB5 = lv_tabview_add_tab(ui_TABS, "TAB5");
    lv_obj_clear_flag(ui_TAB5, LV_OBJ_FLAG_SCROLLABLE);      /// Flags

I did try this already but no success. ```
lv_obj_add_event_cb(ui_TAB1, ui_event_TAB1, LV_EVENT_VALUE_CHANGED, NULL);

Regards
Narendra SIngh

Hello,

I understand now what you are trying to do. It would still be possible to detect which tab has been pressed. The documentation mentions this lv_tabview_get_tab_act() function.

I have edited your code, give it a try (it is not nicely formatted but I think you understand):

ui_TABS = lv_tabview_create(ui_TABS_root_PANEL, LV_DIR_TOP, 48);
    lv_obj_set_width(ui_TABS, 663);
    lv_obj_set_height(ui_TABS, 48);
    lv_obj_set_x(ui_TABS, 5);
    lv_obj_set_y(ui_TABS, -474);
    lv_obj_set_align(ui_TABS, LV_ALIGN_BOTTOM_LEFT);
    lv_obj_clear_flag(ui_TABS, LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_SCROLL_ELASTIC | LV_OBJ_FLAG_SCROLL_MOMENTUM |
                      LV_OBJ_FLAG_SCROLL_CHAIN);     /// Flags
    lv_obj_set_style_radius(ui_TABS, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(ui_TABS, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ui_TABS, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_color(ui_TABS, lv_color_hex(0x868080), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_opa(ui_TABS, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_width(ui_TABS, 1, LV_PART_MAIN | LV_STATE_DEFAULT);


	#define TAB_CNT 5
	
	lv_obj_t* tabs[TAB_CNT];

    ui_TAB1 = lv_tabview_add_tab(ui_TABS, "TAB1");
	tabs[0] = ui_TAB1;

    ui_TAB2 = lv_tabview_add_tab(ui_TABS, "TAB2");
    lv_obj_clear_flag(ui_TAB2, LV_OBJ_FLAG_SCROLLABLE);      /// Flags
	tabs[1] = ui_TAB2;

    ui_TAB3 = lv_tabview_add_tab(ui_TABS, "TAB3");
	tabs[2] = ui_TAB3;


    ui_TAB4 = lv_tabview_add_tab(ui_TABS, "TAB4");
    lv_obj_clear_flag(ui_TAB4, LV_OBJ_FLAG_SCROLLABLE);      /// Flagss
	tabs[3] = ui_TAB4;

    ui_TAB5 = lv_tabview_add_tab(ui_TABS, "TAB5");
    lv_obj_clear_flag(ui_TAB5, LV_OBJ_FLAG_SCROLLABLE);      /// Flags
	tabs[4] = ui_TAB5;
	
lv_obj_add_event_cb(ui_TABS, ui_event_TABS, LV_EVENT_VALUE_CHANGED, NULL);

void ui_event_TABS(lv_event_t * e){
	int index = lv_tabview_get_tab_act(ui_TABS);
	
	if (index < TAB_CNT) {
		lv_obj_t* tab = tabs[index];
		
		/* Do something with tab */
	}
	
  }

Alternatively you might try to figure out which tab has been pressed using the target of the event in that callback. I am not sure how exactly this works with the tabview.

1 Like

Hi Tinus,
Thanks for your quick support. It helped and it works my intended way i.e. i am able to find which tab has been pressed.
The mistake i was doing initially was i was setting event for individual tabs which doesn’t work

lv_obj_add_event_cb(ui_TAB1, ui_event_TAB1, LV_EVENT_ALL, NULL);
lv_obj_add_event_cb(ui_TAB2, ui_event_TAB2, LV_EVENT_ALL, NULL);

which should have been done like

lv_obj_add_event_cb(ui_TABS, ui_event_TABS, LV_EVENT_VALUE_CHANGED, NULL);  // LV_EVENT_ALL also works instead of LV_EVENT_VALUE_CHANGED though

and then as you mentioned, in callback event of ui_event_TABS, we can find the index of tab which has been pressed using

lv_tabview_get_tab_act(ui_TABS);

Thanks a lot for your help.
As i said i have about 20 widgets like buttons,arc,panels, image buttons etc which are common for all the tabs, hence i thought i could make common widgets for all the tabs instead of creating 20 widgets x5tabs and access them using variables.
This way i could save lots of memory in creating just 20 widgets instead of 100 widgets for 5tabs since i need same widgets for all the tabs.
I was struggling a lot to read the tab index. Finally i could. Its amazing.
Regards
Narendra Singh