Prevent LVGL from updating the whole screen when only one object is changed

Description

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

NRF5340DK with waveshare_epaper_gdew075t7 E-Ink

What LVGL version are you using?

v8.2.0

What do you want to achieve?

I want to add calendar entries added to the screen with only updating the single entry itself.
But the whole screen goes black-white-black … and updates completely when invoking the lv_task_handler() . It works fine with any other element on the screen.
The base object is the “wallpaper”, on which the object “calendar_window” is used to arrange the calendar entries.

Whats funny is, that the first entry appears correct and only its area of the e-ink is changed. When the second entry is added and lv_task_handler() is called again, the whole screen gets updated. But i cant reproduce this state. Now every entry triggers the whole screen refresh.

What have you tried so far?

I tried to change many style attributes, reduced the size of the appointment entries. And it seems to have an influence, but i dont get the correlation.
Also i deactivated many objects in the background to minimize the error reasons.

Also i tried to initialize the objects once in the beginning and only change the label, but same behaviour.

Code to reproduce

Unfortunately the code is very big, so it cant be reproduced easily.

This is the code, that is called multiple times, once for every entry:

   int halign = 60;
    int valign = 4 + 35 + (40 * (appstart - 8));
    int width  = WINDOW_WIDTH - halign - 4 - 20;
    int height = 40 * (append - appstart) - 3 - 20;


    calendar_appointment_slot[slot] = lv_obj_create(calendar_window);
    lv_obj_add_style(calendar_appointment_slot[slot], &style_appointment, 0);
    lv_obj_set_size(calendar_appointment_slot[slot], width, height);
    lv_obj_align(calendar_appointment_slot[slot], LV_ALIGN_TOP_LEFT, halign, valign);

    lv_task_handler();

    calendar_appointment_label[slot] = lv_label_create(calendar_appointment_slot[slot]);
    lv_label_set_text(calendar_appointment_label[slot], lecture);
    lv_obj_align(calendar_appointment_label[slot], LV_ALIGN_CENTER, 0, 0);

    lv_task_handler();

Does anyone have an idea what things could cause this behaviour?

Ignore the lv_task_handler(); in the middle, that was just a try to see the behaviour.

Now i initialize objects before use and set their size and allignment, so that they arent visible.

    for (int i = 0; i < APPOINTMENT_SLOTS; i++)
    {
        calendar_appointment_slot[i] = lv_obj_create(calendar_window);
        lv_obj_add_style(calendar_appointment_slot[i], &style_appointment, 0);
        lv_obj_set_size(calendar_appointment_slot[i], 0, 0);
        lv_obj_align(calendar_appointment_slot[i], LV_ALIGN_TOP_LEFT, 0, 0);
    }

Then, instead of deleting the objects i do the same.

static void clear_appointment(int slot)
{
    lv_obj_set_size(calendar_appointment_slot[slot], 0, 0);
    lv_obj_align(calendar_appointment_slot[slot], LV_ALIGN_TOP_LEFT, 0, 0);

    lv_task_handler();
}

When creating the entry, i only set its size and allignment again.

   lv_obj_set_size(calendar_appointment_slot[slot], width, height);
   lv_obj_align(calendar_appointment_slot[slot], LV_ALIGN_TOP_LEFT, halign, valign);

Deleting works fine and only updates the used pixels.
But creating entries sometimes updates the whole screen, allthoug only their allignment changes to a bigger y-value, so the entries are below. You can see it in the video as an example.
example

Thank you everyone for the help and suggestions!
Unfortunately they didnt help me, but i managed to figure out the solution on my own.
For anyone having similar problems in the future:

Objects have to be initialized first. You arent allowed to delete them and create new ones otherwise the whole screen will update.
I set the size to zero so they arent displayed and had about 40 objects with different allignments (initialized).
This was neccessary, because moving / realligning an object (with too much distance from previous position) causes the whole screen to refresh aswell.
So i always chose the nearest object and set its size to display it.
The same goes for “deleting” objects, just set its size to zero (check that this really worked → taskhandler + get_width) and only the concerning pixels get updated.

LVGL has an efficient mechanism for this.

Method:

  1. Redraw changed item(s)
  2. Invalidate item(s) or their container.

In code:

lv_obj_t *Container;
lv_obj_t *Button;
lv_obj_t *Label;
// Assume Container contains Label + Button
InfoPrint( TxtBuf, sizeof TxtBuf ); // Write updated info into buffer ‘TxtBuf’.
lv_label_set_text( Label, TxtBuf ); // Update Label text.
ButtonDisable( Button ); // Grey out Button.
lv_obj_invalidate( Container ); // Call Container ‘dirty’ to have it redrawn.
// The next regular lv_task_handler() call will redraw only the invalidated parts without side effects.
// I guess invalidating each separate object would have the same effect.

Thank you!

Do you think this method will work, if the child objects of the container are deleted and others newly created / initalized?
And would you use one container for (in my case) all calendar entries or one container per entry?
Not asking because of efficiency, but because of unwanted side effects.

YW marviwolf,

Q: Do you think this method will work, if the child objects of the container are deleted and others newly created / initalized?
A: I guess it will work. If you delete and create new objects because the contents changes drastically (i.e. button replaced by text), that is necessary.
But there is no need to delete and recreate the SAME object just to update its contents (i.e. a text replacement). As you can see in my code, just reprint/update the contents and invalidate that object suffices (if many objects to be invalidated, then invalidate the container object).

Q: And would you use one container for (in my case) all calendar entries or one container per entry?
A: If a calendar entry contains several user editable objects, I would invalidate each object individually. This depends on your design. Creating containers with only 1 object is pointless, then invalidate the object directly.

HTH

Thanks!
In my case it is about changing the size and the place of the object, so a little bit more drastic than just changing the text.
But your proposal still sounds like the way to go.
Im afraid i cant change my implementation anymore as it is finally working, so i cant test your idea.

YW,

You can always exclude a small piece of your code by commenting out (or conditional compilation) to test it. The (re)size and position routines are already there and invalidating works for all kinds of changes.
Just try a small piece, takes you 15 mins.
I had to make the same change and took me just 2-3 hours in total.

You do what VNC do, you create a second buffer, and on lvgl_flush_cb you compare them and act according to the changed between them, that way you can control in what conditions the display need partial or full refresh and the timing, that way you let lvgl to do it’s thing :sweat_smile:.