How to clear all screens?

Description

What MCU/processor/board and compiler are you using?

DISCO-F746NG | Mbed with Mbed studio compiler.

What version of LVGL are you using?

8.3.4

What do you want to accomplish?

Good morning,
I want to successively display the examples included in the LVGL library. The major difficulty is to correctly release the resources between each example.
I would like to know if it is possible to erase all the screens created previously without knowing their numbers and identifiers?
Is there a function that would remove all inactive screens?
Is there a function that would allow to have the number of screens created? Or the number of objects that have no parent? I think it would be the same, it would allow using lv_obj_del().

What have you tried so far?

I saw that the lv_obj_clean() function allows to delete all the children of a screen (with the lv_scr_act() parameter for the active screen).
The lv_obj_del() and lv_obj_del_async() functions are used to delete a screen, except the active screen.

Marc.

Hello!

I think the best way is to have a handler for each screen and a structure that contains the elements for each one.

In my application I created a function responsible for initializing and deallocating the resources based on a variable that has the current and the old screen.

It is important to note that in this model each screen has a function that initializes its elements.

I will leave my code snippet for you to check.


/* ************************************************************
 * PRIVATE TYPES DEFINITION                                   *
 * ***********************************************************/

/**
 *
 */
typedef struct {	
	lv_obj_t *btnEnterBack;
	lv_obj_t *btnUp;
	lv_obj_t *btnDown;
} screenYourScreen1Itens_t;

/**
 *
 */
typedef struct {	
	lv_obj_t *btnEnterBack;
	lv_obj_t *btnUp;
	lv_obj_t *btnDown;
} screenYourScreen2Itens_t;

/**
 *
 */
typedef enum {
    SCREEN_YOUR_SCREEN_1 = 0,
	SCREEN_YOUR_SCREEN_2,
	SCREEN_YOUR_SCREEN_3,

	SCREEN_ENDINDEX,

	SCREEN_INVALID_VALUE,
} screensList_e;

/**
 *
 */
typedef struct {	
	lv_obj_t *btnEnterBack;
	lv_obj_t *btnUp;
	lv_obj_t *btnDown;
} screenYourScreen3Itens_t;

/* ************************************************************
 * PRIVATE GLOBAL VARIABLES DEFINITION                        *
 * ***********************************************************/
 
static lv_obj_t *scrYourScreen1 = NULL;
static screenYourScreen1Itens_t screenYourScreen1Itens;

static lv_obj_t *scrYourScreen2 = NULL;
static screenYourScreen2Itens_t screenYourScreen2Itens;

static lv_obj_t *scrYourScreen3 = NULL;
static screenYourScreen3Itens_t screenYourScreen3Itens;

static screensList_e m_oldScreen = SCREEN_INVALID_VALUE;
static screensList_e m_curScreen = SCREEN_INVALID_VALUE;


/* ************************************************************
 * DEFINITION OF PRIVATE FUNCTIONS                            *
 * ***********************************************************/

void scrYourScreen1Init(void) {

	lv_obj_t *label;

	screenYourScreen1Itens.btnEnterBack = lv_btn_create(scrYourScreen1);
	

	lv_obj_align(screenYourScreen1Itens., LV_ALIGN_BOTTOM_LEFT, 0, 0);
	label = lv_label_create(screenYourScreen1Itens.);
	lv_label_set_text_fmt(label, "%s", "Test");
	lv_obj_center(label);
	lv_obj_set_size(screenYourScreen1Itens., lv_pct(33), lv_pct(16));
	lv_obj_set_style_bg_color(screenYourScreen1Itens., lv_color_black(), LV_PART_MAIN);
	lv_obj_set_style_text_color(label, lv_color_white(), 0);	
}

/**
 *
 */
static void navigateToScreen(screensList_e screenToGo) {

	if(m_curScreen != screenToGo) {

		switch (screenToGo) {

			/**************************/
			case SCREEN_YOUR_SCREEN_1:				
				scrYourScreen1Init();
				lv_disp_load_scr(scrYourScreen1);

			break;
			/**************************/
			case SCREEN_YOUR_SCREEN_2:
				scrYourScreen2Init();
				lv_disp_load_scr(scrYourScreen2);

			break;
			/**************************/
			case SCREEN_YOUR_SCREEN_3:
				scrYourScreen3Init();
				lv_disp_load_scr(scrYourScreen3);

			break;
			/**************************/
			default:
			break;
			/**************************/
		}

		m_oldScreen = m_curScreen;
		m_curScreen = screenToGo;

		switch (m_oldScreen) {

			/**************************/
			case SCREEN_YOUR_SCREEN_1:
				lv_obj_del(scrYourScreen1);
				break;
			/**************************/
			case SCREEN_YOUR_SCREEN_2:
				// if you use a timer, can delete here lv_timer_del(timerHandler);
				lv_obj_del(scrYourScreen2);
			break;
			/**************************/
			case SCREEN_YOUR_SCREEN_3:				
				lv_obj_del(scrYourScreen3);
			break;
			/**************************/
			
			default:

			break;
		}
	} 
}

// In your application you just need call the navigateToScreen() with properly screen like:

navigateToScreen(SCREEN_YOUR_SCREEN_1);```

Thank you for your answer.
Sorry to only answer now, I only just tried the code you posted. :confused:
This code looks interesting, but I can’t get it to work, it looks like there are several errors in this code.

After looking at the Create screens part of this page: Objects — LVGL documentation I replaced the line:
static lv_obj_t * scrYourScreen1 = NULL;
by

static lv_obj_t * scrYourScreen1 = lv_obj_create(NULL);

But even this single line in my code causes my target to crash, despite what I read in the documentation. :thinking:

I call these libraries in my tests:

#include "mbed.h"
#include "lvgl.h"
#include "hal_stm_lvgl/tft/tft.h"
#include "hal_stm_lvgl/touchpad/touchpad.h"

We forgot the initializations:

lv_init(); //Initialize the LVGL
tft_init(); //Initialize display
touchpad_init(); //Initialize touchpad

after this this line works.

static lv_obj_t * scrYourScreen1 = lv_obj_create(NULL);

Yes, but I can’t put this line in the global declarations and put the init in the main() because they have to be called before.

Sorry for late reply. I dont see notifications. Do you need some help?

Hi Marc,

Is your " How to clear all screens?" problem solved?
I have a solution.

BR JJ

Hello everyone !

Here is my best solution to manage screens and remove the previous screen automatically when I load a new one :

gui_loader.h

#ifndef GUI_PAGE_LOADER_H
#define GUI_PAGE_LOADER_H

#define CAT_NAME_FUN(name, fun) name##fun
#define LOAD_PAGE(page) CAT_NAME_FUN(page, _create())  // this will add _create to the name of the page in the enumeration 
#define DEL_PAGE(page) CAT_NAME_FUN(page, _delete()) // this will add _delete 
// so, LOAD_PAGE will call a function gui_page_whatever_create()
// and  DEL_PAGE will call a function gui_page_whatever_delete()

// and both of this functions should be contained in each page screen.

/* INCLUDES */
#include "page_home.h"
#include "page_prepare.h"
#include "page_wifi.h"

/* PAGES */
typedef enum {
gui_page_home,
gui_page_prepare,
gui_page_wifi
} gui_pages_t;

gui_pages_t gui_loader_get_current_page();
void gui_loader_set_current_page(gui_pages_t page);

#define NAVIGATE_TO(parent, page) {LOAD_PAGE(page); DEL_PAGE(parent); gui_loader_set_current_page(page);}

#endif

gui_loader.c

#include "gui_page_loader.h"

static gui_pages_t current_page = gui_page_home;

gui_pages_t gui_loader_get_current_page()
{
       return current_page;
}

void gui_loader_set_current_page(gui_pages_t page)
{
       current_page = page;
}

Now, each time you create a new page screen (new header/source file) you have to add 2 methods :

  • gui_page_yourpagename_create()
  • gui_page_yourpagename_delete()

Example of my wifi page :

lv_obj_t *gui_page_wifi_create();
void gui_page_wifi_delete();

Source file:

static lv_obj_t *wifi_screen = NULL;

/* create function */
lv_obj_t *gui_page_wifi_create()
{
	wifi_screen = lv_obj_create(NULL, NULL);
	/*  add your widgets here   */

	lv_scr_load(wifi_screen);
	return wifi_screen;
}

/* delete function */
void gui_page_wifi_delete()
{
	if (wifi_screen != NULL) {
		lv_obj_del(wifi_screen);
		wifi_screen = NULL;
	}
}

finally,
NAVIGATE_TO(gui_page_home, gui_page_wifi);

This will load wifi page first then remove home page (or screen).