How to load screens when using multiple displays

Description

I am currently having issues when creating multiple screens for multiple displays.

I create all displays, then all the screens, before iterating through loading each one onto its respective display by calling lv_disp_set_default, followed by lv_scr_load. This, however, only displays the content on the display that I created first (with the last screen being shown, as it was last to load).

According to the Overview → Displays → Screens section of the documentation, lv_scr_load should operate on the default display, however it appears that the screens are always loaded onto the display that was the default when the display was initialised. When looking at the LVGL source, this can be explained, as lv_scr_load calls lv_disp_load_scr, which calls lv_obj_get_disp to determine the display to draw the screen to.

Furthermore, the same section of the documentation lists lv_disp_load_scr as a separate function to lv_scr_load, and shows it as having 2 arguments:

lv_disp_load_scr(disp, scr)

However the LVGL source shows that lv_disp_load_scr only has 1 argument (the screen):

lv_disp_load_scr(scr)

Are these discrepancies due to the documentation being out of date? Or am I missing something here?

Basically, is there any way of loading screens to different displays, having created them at once, or do I have to set the correct default display before creating each screen?

Thanks in advance for any help!

What LVGL version are you using?

8.0.2

After some more digging in the LVGL source code (specifically the lv_obj_class_create_obj function definition), it does appear that the screens are assigned to the default screen when they are created, rather than when they are loaded.
It seems, therefore, that perhaps that particular section of the documentation needs updating to reflect this (and provide the correct function prototype for lv_disp_load_scr. I am happy to try updating it myself and create a PR, if that’s the best way forward.

In terms of my initial problem (of needing to load screens to particular displays after creating them, I have altered lv_disp_load_scr with the following changes, which works (though doesn’t handle the removing of the screen from the previous display it was assigned to, and probably has other issues).

void lv_disp_load_scr(lv_obj_t * scr)
{
    //Start of changes
    lv_disp_t * d = lv_disp_get_default();
    d->screen_cnt++;
    d->screens = lv_mem_realloc(d->screens, sizeof(lv_obj_t *) * d->screen_cnt);
    d->screens[d->screen_cnt - 1] = scr;
    //End of changes

    if(!d) return;  /*Shouldn't happen, just to be sure*/
    d->act_scr = scr;

    lv_obj_invalidate(scr);
}

Does anyone have a better way of achieving this? Or is it best to just accept that I should set the correct default display before creating the screen object?

Hi,friend,I use your method to load the new screen, but there is no effect, can you teach me how to use your method ?
//bar1 = lv_bar_create(lv_scr_act());//

lv_obj_t *scr1 = lv_disp_get_scr_act(dis1);



lv_disp_load_scr2(scr1); //your function

bar1 = lv_bar_create(scr1);

lv_obj_set_size(bar1,  50, 10);

lv_obj_align(bar1,LV_ALIGN_TOP_RIGHT, 0, 0);

lv_bar_set_range(bar1,0,60);

lv_bar_set_value(bar1, 0, LV_ANIM_OFF);

lv_init();

/* Initialize SPI or I2C bus used by the drivers */

lvgl_driver_init();

lv_color_t* buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);

// memset(buf1,0x00ff,DISP_BUF_SIZE * sizeof(lv_color_t));

assert(buf1 != NULL);

/* Use double buffered when not working with monochrome displays */

#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME

lv_color_t* buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);

//memset(buf2,0x00ff,DISP_BUF_SIZE * sizeof(lv_color_t));

assert(buf2 != NULL);

#else

static lv_color_t *buf2 = NULL;

#endif

static lv_disp_draw_buf_t disp_buf;

uint32_t size_in_px = DISP_BUF_SIZE;

#if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820 \

|| defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_JD79653A    \

|| defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D     \

|| defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306

/* Actual size in pixels, not bytes. */

size_in_px *= 8;

#endif

/* Initialize the working buffer depending on the selected display.

 * NOTE: buf2 == NULL when using monochrome displays. */

lv_disp_draw_buf_init(&disp_buf, buf1, buf2, size_in_px);

lv_disp_drv_t disp_drv;

lv_disp_drv_init(&disp_drv);

disp_drv.hor_res=LV_HOR_RES_MAX;

disp_drv.ver_res=LV_VER_RES_MAX;

disp_drv.flush_cb = disp_driver_flush;

disp_drv.draw_buf = &disp_buf;

dis1 = lv_disp_drv_register(&disp_drv);

/*********cj_def***********/

disp_spi_add_device_cs(TFT_SPI_HOST,19);//new_display

disp_driver_init();

lv_color_t* buf1_2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);

assert(buf1_2 != NULL);

static lv_disp_draw_buf_t disp_buf2;

lv_disp_draw_buf_init(&disp_buf2, buf1_2, NULL, DISP_BUF_SIZE);

lv_disp_drv_t disp_drv2;

lv_disp_drv_init(&disp_drv2);

disp_drv2.hor_res=LV_HOR_RES_MAX;

disp_drv2.ver_res=LV_VER_RES_MAX;

disp_drv2.flush_cb = disp_driver_flush;

disp_drv2.draw_buf = &disp_buf2;

dis2 = lv_disp_drv_register(&disp_drv2);

 /*********cj_def***********/