Search code examples
pythonfunctiontkinterdelaysleep

Use Tkinter After To Get Return Value And Return It Again


I needed a delay before calling a function and getting its return value. But time.sleep is freezing the tkinter GUI so i used tkinter.after. tkinter.after is working and won't freeze the window, but I cannot get the return value of the function that I've called. Because after I delayed and got the returned value, I've to return it again to the other function that called this function.

I've been struggling with this, please if any of you know any solutions, help me

This is the basic example of whats going on

import tkinter as tk
from time import sleep


def getvalue():

    value = "haha"

    sleep(3)

    return value


def printvalue():

    value = getvalue()

    print(value)



app = tk.Tk()
app.geometry("500x300")

button = tk.Button(app, text="print value", command=printvalue)
button.pack()

app.mainloop()

Solution

  • For this simple example I would use tkinter.after() to run function with delay. And all code afer getting data I would move to second function which is executed by tkinter.after().

    But your real code can be more complex and it can be hard to split it.

    import tkinter as tk
    
    def getvalue():
        return "haha"
    
    def second_part(other):
        print('after delay')
    
        value = getvalue()
    
        # code moved from first part
        print('value:', value)
        print('other:', other)
        button['text'] = value
    
    def print_value():
        # first part makes some calculation
        other_variable = 'some value'
    
        print('before delay')
    
        # run function with delay and send all data from first part
        app.after(3000, second_part, other_variable)
    
        # rest of code moved to second_part
    
    app = tk.Tk()
    
    button = tk.Button(app, text="print value", command=print_value)
    button.pack()
    
    app.mainloop()
    

    EDIT: If you have problem to use tkinter.after() then you can try to use Thread to run print_value which will have to wait for getvalue().

    But Thread sometimes may have problem to access GUI widgets in main thread.

    import tkinter as tk
    from time import sleep
    import threading
    
    def getvalue():
        sleep(3)
        return "haha"
    
    def print_value():
        # first part makes some calculation
        other_variable = 'some value'
    
        print('before delay')
    
        value = getvalue()
    
        print('after delay')
    
        print('value:', value)
        print('other:', other_variable)
        button['text'] = value
    
    
    def start_thread():
        t = threading.Thread(target=print_value)
        t.start()
    
    app = tk.Tk()
    
    button = tk.Button(app, text="print value", command=start_thread)
    button.pack()
    
    app.mainloop()
    

    I was thinking about asyncio which has non-blocking asyncio.sleep() but asyncio needs to run own loop which would block mainloop() so it would have to run in Thread.