Search code examples
pythonpython-3.xtkinterraspberry-pi3guizero

guizero Raspberry Pi: button -> command sequence problems


Required: pressing a button on a guizero App should first set a text value, then perform a function (here a simple time.sleep(); originally a subprocess); after performing the function a result text should be displayed;

#!/usr/bin/python3
# -*- coding: utf-8 -*-

from guizero import App, PushButton, Text
import subprocess
import time

# Action you would like to perform
def counter0():
    global s0
    text0.value = int(text0.value) + 1  # works
    text1.value = s0                    # works

def counter1():
    global s0
    text1.value = s0       # display a status value - but does not (!)
    time.sleep(1)          # originally a subprocess is called here; works
    text1.value = "ready"  # only diplays this after a delay

s0="start something after pressing butt1"

app = App("Hello world", layout="grid")

text0 = Text(app, text="1", align="left", grid=[0,1])
text1 = Text(app, text=s0, align="left",grid=[0,8] )
butt1 = PushButton(app, text="Button", command=counter1, align="left", grid=[0,2])
text0.repeat(10000, counter0)  # Schedule call to counter() every 1000ms

app.display()

Most likely I did not understand the idea behind guizero. Any Ideas how to manage such requrements?


Solution

  • If I understand your question correctly, your specific problem is here:

        text1.value = s0       # display a status value - but does not (!)
    

    This doesn't work because the guizero framework is executing the function synchronously: no other code executes -- including the code to update the display -- until the function has returned.

    If you want to:

    • Display a message before running a command with subprocess
    • Run some command
    • Display a message after the command completes

    Then you will need to rewrite your logic so that you're app isn't waiting for `counter1 to complete. One option for running code asynchronously is to run it in a separate thread. For example:

    from guizero import App, PushButton, Text
    import threading
    import time
    
    
    # Action you would like to perform
    def counter0():
        global s0
        text0.value = int(text0.value) + 1  # works
        text1.value = s0                    # works
    
    
    def run_command():
        time.sleep(1)          # originally a subprocess is called here; works
        text1.value = "ready"  # only diplays this after a delay
    
    
    def counter1():
        global s0
        text1.value = "Running command..."
        threading.Thread(target=run_command).start()
    
    
    s0 = "start something after pressing butt1"
    
    app = App("Hello world", layout="grid")
    
    text0 = Text(app, text="1", align="left", grid=[0, 1])
    text1 = Text(app, text=s0, align="left", grid=[0, 8])
    butt1 = PushButton(app, text="Button", command=counter1,
                       align="left", grid=[0, 2])
    text0.repeat(10000, counter0)
    
    app.display()
    

    Running the above code will give you the following behavior:

    enter image description here