peterhinch / micropython-micro-gui

A lightweight MicroPython GUI library for display drivers based on framebuf, allows input via pushbuttons. See also micropython-touch.
MIT License
269 stars 40 forks source link

HELP: The Screen.change() #5

Closed petrkr closed 2 years ago

petrkr commented 2 years ago

In documentation is The Screen.change() classmethod returns immediately but actually that call is blocking until window is closed.

So how I can do some semi-automatic code like in workflow as this:

after init is done, I want to have some "main loop" which will wait for some user input (but not screen input). Like for example some interrupt or some other device (received text from UART, touched button that is NOT connected to display class, receive anything from MQTT...)

Until now I know I can use NanoGUI instead .... but now ...

for example user will send over UART some question. I want to show dialog (or screen or whatever) with buttons "Yes/No/Cancel/Whatever" or some listbox and now this microgui came to game... Because you have really nice done those windows, menu etc widgets... So I wanna somehow interact with it (yes this part I already know I can use call backs, that is pretty nice)...

But I do not know how to combine both threads/codes beside each other.

If I understand it well, I have to do some "BaseScreen" where I will do everything and I will do some my "loop" task or whatever?

And what if BaseScreen crash? So do it like

while True:
  Screen.change(MainScreen)

?

Thanks for any advice

petrkr commented 2 years ago

Meanwhile I tried to do somethinglike this

class BootScreen(Screen):
    def __init__(self):
        super().__init__()
        wrilabel = CWriter(ssd, arial35, YELLOW, BLACK)
        writb = CWriter(ssd, arial10, GREEN, BLACK)
        col = 2
        row = 2
        Label(wrilabel, row, col, 'Starting')

        row += 45
        self._tb = Textbox(writb, row, col, 154, 7)
        self.reg_task(self.main())

    async def main(self):
        await asyncio.sleep_ms(10)
        self._tb.append("Loading wifi")
        await asyncio.sleep_ms(0)
        from utils.wifi_connect import WiFiConnect
        self._tb.append("Connecting wifi")
        await asyncio.sleep_ms(0)
        wc = WiFiConnect()
        wc.connect()
        self._tb.append("Connecting wifi... Done")
        self.shutdown()

Screen.change(BootScreen)

Is that how I should work with this?

peterhinch commented 2 years ago

My documentation is indeed unclear. Screen.change blocks when opening the base screen, but does not block when opening further screens. When the base screen is closed, the GUI itself is shut down and control returns to the REPL. Typical embedded applications provide no means of closing the base screen.

Starting coroutines with reg_task as you are doing above is correct, but I would avoid closing the base screen except where you want to restore the REPL for test purposes.

petrkr commented 2 years ago

My documentation is indeed unclear. Screen.change blocks when opening the base screen, but does not block when opening further screens. When the base screen is closed, the GUI itself is shut down and control returns to the REPL. Typical embedded applications provide no means of closing the base screen.

Starting coroutines with reg_task as you are doing above is correct, but I would avoid closing the base screen except where you want to restore the REPL for test purposes.

So better way would be do Base Screen without close button and let it act as "main loop". So this screen will be "black" or maybe with some "background picture" or whatever.

And this "bootscreen" will be child of BaseScreen, right?

I had now vision to do BootScreen and after it's shutdown run MainScreen (app).

peterhinch commented 2 years ago

When you first open a screen the uasyncio scheduler is started. If you ever close that screen, it is stopped and control returns to the REPL.