How to change between screens?

Hi everyone,

This question has been dealed a lot, but I cannot found a solution that’s working in LVGL.
I read the documentation but there is no example about how switching screens.

Here is what I want to do:
I have “screen_General”, and a list on it. Depending of the choice on the list, I want to change screens (screen_MotDePasse" for example for choice “Confort”). I found this topic https://forum.lvgl.io/t/how-to-switch-screens-correctly/12337/6 which seems to be a good solution and try to adapt it to me but it does not work.

For now, my code works until I choose “Confort” in the list which leads to nothong (or maybe it’s crashing). “Screen_General” is not deleted and “Screen_MotDePasse” is not loaded.

Here is my code. I run it on LVGL simulator:
Change_screens_test.c (14.4 KB)

Welcome
you miss , delete object from self isnt good idea

       if (strcmp(buf,"Confort")==0)
       {
            lv_obj_del(screen_General);
            create_screen_2(0);
       }

if you realy require del place it in create2. Plus best practice is create2 and load it as last cmd, not first. And after this load you can try del, but better is place del in unload callback…

Why do you use screen deletion?
I think that you can create all the screens during initialization, and when events occur, just switch between them using lv_scr_load(screen_x).

if you realy require del place it in create2. Plus best practice is create2 and load it as last cmd, not first.

OK, you suggest as “glory-man” said too to create all screens before and load them after ?

And after this load you can try del, but better is place del in unload callback…

I don’t understand what you mean here. Do you have an example ?

Why do you use screen deletion?
I think that you can create all the screens during initialization, and when events occur, just switch

Because for me, create a screen means put it in memory, which is not good. And when you load the fifth screen, it will save all other screen in memory (even if hidden), right ?

Morerover, as you can see, I have a keyboard for a password in create_screen_2 function. The keyboard has a callback for the button and textarea has a callback too when “OK” is pressed. How can I use create_screen_2 function without calling these callback ?

Here is example init code from Squareline with callback for delete

void ui_Screen4_screen_init(void)
{
    ui_Screen4 = lv_obj_create(NULL);
    lv_obj_clear_flag(ui_Screen4, LV_OBJ_FLAG_SCROLLABLE);      /// Flags
    lv_obj_add_event_cb(ui_Screen4, scr_unloaded_delete_cb, LV_EVENT_SCREEN_UNLOADED, &ui_Screen4);
...
void scr_unloaded_delete_cb(lv_event_t * e)

{

    lv_obj_t ** var = lv_event_get_user_data(e);
    lv_obj_del(*var);
    (*var) = NULL;

}

OK, thanks.

   lv_obj_clear_flag(ui_Screen4, LV_OBJ_FLAG_SCROLLABLE); 

What does this do ? I don’t understand the need of a flag and what “scrollable” is here.
How can I unload a screen ?

And I’m not sure what I have to change in my code in general to change screens.

Up ! Still need help :slight_smile:

If you want to switch to another screen use lv_scr_load().

So create new screen. Use

to add LV_EVENT_SCREEN_UNLOADED event callback. And switch to new screen lv_scr_load(ui_Screen4). And when previous screen will be unloaded LV_EVENT_SCREEN_UNLOADED event occures for previous screen ui_Screen3. As result scr_unloaded_delete_cb() will call and delete previous screen.

OK, thanks glory man, I understand now. A screen is unloaded when another is loaded.
Some others questions now.

lv_obj_clear_flag(ui_Screen4, LV_OBJ_FLAG_SCROLLABLE); 

Do I really need this ? What does this do ?

Also: I need to create screens that are very similar. How can I adapt the init function to not create one function per screen. For example, is it possible to do that ?

static  lv_obj_t * screen_MotdePasse_Initial;
static  lv_obj_t * screen_MotdePasse_Erreur;

lv_obj_t * screen_init(bool screenState)
{
    ui_Screen4 = lv_obj_create(NULL);
    lv_obj_clear_flag(ui_Screen4, LV_OBJ_FLAG_SCROLLABLE);      /// Flags
    lv_obj_add_event_cb(ui_Screen4, scr_unloaded_delete_cb, LV_EVENT_SCREEN_UNLOADED, &ui_Screen4);

    if (screenState == 0)
    {
           //Write some text
    }
    else
    {
           //Write another text
    }

return ui_Screen4;
}

...

void main()
{
   screen_MotdePasse_Initial = screen_init(0);
   screen_MotdePasse_Erreur = screen_init(1);
}

or, if not possible, something like that:

static  lv_obj_t *screen_MotdePasse_Initial;
static  lv_obj_t *screen_MotdePasse_Erreur;

void screen_init(bool screenState, lv_obj_t * screens_MotdePasse)
{
    screens_MotdePasse= lv_obj_create(NULL);
    lv_obj_clear_flag(screens_MotdePasse, LV_OBJ_FLAG_SCROLLABLE);      /// Flags
    lv_obj_add_event_cb(ui_Screen4, scr_unloaded_delete_cb, LV_EVENT_SCREEN_UNLOADED, &screens_MotdePasse);

    if (screenState == 0)
    {
           //Write some text
    }
    else
    {
           //Write another text
    }
}

...

void main()
{
  screen_init(0, screen_MotdePasse_Initial );
  screen_init(1, screen_MotdePasse_Erreur );
}

LV_OBJ_FLAG_SCROLLABLE is a flag to make your screen scrollable. So use it if you need.

Your example is a bit contrary to the original idea.

But in general it can be used

lv_obj_t * screen_init(bool screenState)
{
    lv_obj_t * screen = lv_obj_create(NULL);
    lv_obj_add_event_cb(screen , scr_unloaded_delete_cb, LV_EVENT_SCREEN_UNLOADED, &screen );
// configure screen as need 
    return screen;
}

Why do you say that ? What looks like contrary to you ?
I need to change to screens which are different.
But I need too to update some text (ans list) on same screens depending on choice made on screens. So the only way I find is to create a new screen and load it.

To add more informations about my project:

I have a list (Normal, Confort, etc) on the main screen. Depending on what I choose on list: I can have two behaviours.
1/ I need to load differents screens, then go back to the main screen
2/ I update some informations on the main screen

I also need to update informations on the main screen even if I don’t choose something (the state of a sensor has changed for example)

Up ! gloryman, did you see my answers ?

Moreover, I have another issue. If I load “Screen_mot_de_passe” and then load again “Screen_General” (I don’t use

lv_obj_add_event_cb(.....)

in the init of “Screen_General”)

I have a segmentation fault.
Why ? “Screen_General” shouldn’t be deleted.

it would be useful to see source code of screen init & switching

Below source code for what you asked and if needed my full source code in attachment.

void create_screen_1(byte etat_prgChauffe)
{
  screen_General1 = lv_obj_create(NULL);

  lv_obj_t * liste_Prg_Chauffe = lv_dropdown_create(screen_General1);
  if (etat_prgChauffe == 1)
  {
        lv_dropdown_set_options(liste_Prg_Chauffe, "Normal\n"
                            "Prechauffe\n"
                            "Confort\n"
                            "Off");
  }
  //Some other code for the list here

  lv_obj_align(liste_Prg_Chauffe, LV_ALIGN_CENTER, 85, -30);

  //Some other code here to add elements to screen

}
void create_screen_3(bool ErrorMDP)
{
    screen_MotdePasse_Erreur = lv_obj_create(NULL);
    lv_obj_add_event_cb(screen_MotdePasse_Erreur, scr_unloaded_delete_cb, LV_EVENT_SCREEN_UNLOADED, &screen_MotdePasse_Erreur);

}
lv_obj_t * create_screen_2(bool ErrorMDP)
{
    lv_obj_t * screen_MotdePasse = lv_obj_create(NULL);
    lv_obj_add_event_cb(screen_MotdePasse, scr_unloaded_delete_cb, LV_EVENT_SCREEN_UNLOADED, &screen_MotdePasse);

    //Some other code here to add elements to screen

    return screen_MotdePasse;

Switching 1:

static void choix_PrgChauffe(lv_event_t * e)
{

  lv_event_code_t code = lv_event_get_code(e);
  lv_obj_t * choix = ( lv_obj_t *) lv_event_get_target(e);
   if(code == LV_EVENT_VALUE_CHANGED)
   {
        enterPrgChauffe = 1;

       if (strcmp(buf,"Confort")==0)
       {
            screen_MotdePasse_Initial1 = create_screen_2(0);
            lv_scr_load(screen_MotdePasse_Initial1);
            //Screen switch fine from Screen_General1 to  screen_MotdePasse_Initial1 here

       }

Switching 2:

static void textarea_event_handler(lv_event_t * e)
{
    lv_obj_t * ta = lv_event_get_target(e);
    LV_UNUSED(ta);
    char*texte = lv_textarea_get_text(ta);
    LV_LOG_USER("Enter was pressed. The current text is: %s", texte);
    if (strcmp(texte,"2785")==0)
    {
        lv_scr_load(screen_General1); 
        //Switch back to screen_General1 create seg fault
    }
    else
    {
        create_screen_3(1); // the aim is to use only create_screen2() then, and delete create_screen_3() function
        lv_scr_load(screen_MotdePasse_Erreur);
        //Switch to screen_MotdePasse_Erreur create seg fault too
    }

source_code.c (20.6 KB)

use marked unused is compiler absurd…

This come from the official documentation… https://docs.lvgl.io/master/examples.html#textarea

And I’m not sure this answer to my questions or help in my problem.

try

static void textarea_event_handler(lv_event_t * e)
{
    lv_obj_t * ta = lv_event_get_target(e);
    LV_UNUSED(ta);
 //   char*texte = lv_textarea_get_text(ta);
 //   LV_LOG_USER("Enter was pressed. The current text is: %s", texte);
    if (strcmp(texte,"2785")==0)

is segfault too? And from your no info about platform etc. nobody help

Second example won’t work as “texte” is not declared. Moreover, the issue occurs when I switch to the next screen. I can use the textarea fine.

First message said that I’m on LVGL simulator. But to be more precise, I’m on CodeBlocks, as LVGL documentation recommends.

I don’t understand why it’s so complicated to change between two screens and why the documentation has no info about that…

Ok sorry i skip texte in next line then start only with test screen change

static void textarea_event_handler(lv_event_t * e)
{
    if (1)
    {
        lv_scr_load(screen_General1); 
        //Switch back to screen_General1 create seg fault
    }
}

when this crash too then comment out delete because this is called immediately after load General…

//    lv_obj_add_event_cb(screen_MotdePasse, scr_unloaded_delete_cb, LV_EVENT_SCREEN_UNLOADED, &screen_MotdePasse);