Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flag variable and state variable support for [create_screen_...] functions #645

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

FourLeafTec
Copy link

If the variable is only used in the tick function, screen switching may cause state flickering. Initially, the widget state is the default lvgl state, and it won't switch to the variable-specified state until the next tick, resulting in flickering.

Therefore, it's necessary to get the variable value and set the state once during screen creation.

As shown in the image below.
截屏2024-11-22 16 25 46

@mvladic
Copy link
Contributor

mvladic commented Nov 22, 2024

Your code doesn't work in all cases. It works only if expression for Hidden flag or Disabled state is simple expression where only native variable is used. But expression can be anything, at least if you are using EEZ Flow.

Alternative way to prevent flickering is to call ui_tick() not only in a loop after lv_timer_handler or lv_task_handler, but also immediately after calling ui_init()

@FourLeafTec
Copy link
Author

FourLeafTec commented Nov 23, 2024

In my case, I use lvgl in pure C, so I can't use EEZ Flow.I'm really sorry I didn't think about how the EEZ Flow would affect this.

I think I need to describe my problem in more detail.

With the limited ram, I can't create all screen's in ui_init(). So i edited the load _screen() function to dynamic create screens

static screen_create screen_creators[] = {
    create_screen_splash_screen,
    create_screen_auto_zero_screen,
    create_screen_main,
    create_screen_load_percent,
    create_screen_settings,
    create_screen_setting_list,
    create_screen_setting_detail,
    create_screen_system_info,
    create_screen_multi_setting,
    create_screen_multi_setting_enable,
    create_screen_multi_setting_guide,
};

void loadScreen(enum ScreensEnum screenId)
{
    currentScreen = screenId - 1;
    screen_creators[currentScreen]();

    lv_obj_t *screen = getLvglObjectFromIndex(currentScreen);

    lv_scr_load_anim(screen, LV_SCR_LOAD_ANIM_FADE_IN, 50, 0, true);

    // ui_tick();
}

And remove create_screen_xxx in create_screens().

Widgets created in the new screen always flicker briefly in their default state before the state set by the global variable is applied.

I'm unsure of the exact cause, but it seems logical to initialize the created state with the value from the global variable.

However, this approach doesn't take into account the expression with the EEZ Flow.

It turns out that I'm facing a similar problem with widget expression property. I haven't updated all widgets either, and I believe we should address this issue together first.

@FourLeafTec
Copy link
Author

Calling ui_tick() after load_screen() should fix my issue. I'd like to do more testing when I return to the lab next Monday.
Please hold this PR for two more days.

@FourLeafTec
Copy link
Author

The test results were unexpectedly strange and did not meet my expectations.

I modified the load_screen() method by moving ui_tick() after create_screen_xxx() and before lv_scr_load_anim().

static screen_create screen_creators[] = {
    create_screen_splash_screen,
    create_screen_auto_zero_screen,
    create_screen_main,
    create_screen_load_percent,
    create_screen_settings,
    create_screen_setting_list,
    create_screen_setting_detail,
    create_screen_system_info,
    create_screen_multi_setting,
    create_screen_multi_setting_enable,
    create_screen_multi_setting_guide,
};

void loadScreen(enum ScreensEnum screenId)
{
    currentScreen = screenId - 1;
    screen_creators[currentScreen]();
    ui_tick();

    lv_obj_t *screen = getLvglObjectFromIndex(currentScreen);

    lv_scr_load_anim(screen, LV_SCR_LOAD_ANIM_FADE_IN, 50, 0, true);
}

Therefore, during lv_scr_load, the widget state should have been updated to the state of the global variable.

However, in the first ui_tick() after lv_scr_load, the widget's display style was still that of create_screen_xxx(). But the cur_val tracked in ui_tick() was already the new state, and it was updated to the expected style in the next rendering frame.

I've noticed that the background colors of the three switches in the header are incorrect in some cases. The first and last images show the expected DISABLED state, as the global variable switch_stat_disable is set to TRUE. However, when I switch between different views, the switches temporarily appear to DEFAULT. This is unexpected behavior.

1561732506921_pic
1571732506922_ pic
1581732506923_ pic

@FourLeafTec
Copy link
Author

That's very strange, lv_obj_remove_state in create_screen_xxx() or after create_screen_xxx() should be same.

But the program isn't working the way it should.

Maybe i need to continue this PR, could I add if (build.assets.projectStore.projectTypeTraits.hasFlowSupport) {...} before my code to continue this PR?

@mvladic
Copy link
Contributor

mvladic commented Nov 25, 2024

I don't know why in your case you are seeing unexpected behavior. I made a project that does (I think) similar thing as yours:

test_pr645.zip

I didn't notice any strange behavior. State of 2 label objects (I purposefully left the state of the middle label unchanged) are turned into DISABLED within ui_tick that is called immediately after screen is created.

@FourLeafTec
Copy link
Author

FourLeafTec commented Nov 25, 2024

In my case,after ui_tick, the state is turned into DISABLED, but sytles by STATE did not change.

In the picture2, breakpoint in ui_tick for cur_val=lv_obj_get_state(...),the cur_val equals new_val.

I had try my project in LVGL Simulator, this problem is not reproducible.

This problem might be related to the underlying rendering logic of LVGL, especially in MCUs with limited single-thread resources.

My platform is gd32f407vet6,168MHz MCU,64k RAM, with screen drive by st7796 16bits parallel interface, screen resolution 480x320.

I think I need to port your test project to my platform for testing, but it might take some time. My schedule is pretty full this week.
: )

@FourLeafTec
Copy link
Author

I ported the test project to my device but couldn't reproduce the issue I encountered. Comparing the two projects, I found that:

  1. In my project, the next screen started rendering on the first ui_tick after loadScreen, which is why it looked wrong.
  2. In the test project, the next screen didn't start rendering until many ui_ticks after loadScreen.
  3. In the test project, after adding more elements to the screen, the next screen didn't start rendering until the second ui_tick after loadScreen, and the issue no longer appeared.

I suspect that my other business logic is consuming too much CPU time, causing LVGL to start rendering in an earlier cycle. I haven't been able to construct a more suitable minimal test case yet, but I believe it should be reproducible. I will continue to try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants