0

I wrote this silly program in python using tkinter where I show a stickman being hit on the head with a hammer by using a button event to change the label's image to the picture showing the stickman being hit for a small time period. The picture Bonk2 is the one that shows this and Bonk1 is just the normal picture if the button hasn't been pressed (both of them I declared as PhotoImages).

The function doing that is given below and I use this function as the command argument for the button BONK -

import time
import tkinter as tk

count = 0

def bonk():
    global count
    print("bonked")
    count += 1
    counter.config(text = "Bonk counter: " + str(count))
    
    if count < 5:
        BONK.config(state = "disabled")
        picture.config(image = Bonk2)
        time.sleep(2) #delay
        picture.config(image = Bonk1) #Changing back the image
        BONK.config(state = "active")
    else:
        picture.config(image = Bonk4)
        BONK.config(state = "disabled")

Now, tkinter won't update the GUI immediately because it actually batches the update to the GUI and executes it after the function call. This means the picture effectively doesn't change from Bonk1 to Bonk2 after the function execution (also the GUI hangs). Is there a workaround where the image changes from Bonk1 to Bonk2 immediately and I can change it back after a delay?

1
  • don't use time.sleep but root.after(2000, other_function) to execute other_function after 2000ms (2s) and in other_function change image - and tkinter will return from current function and it will update all GUI. OR use root.update() before sleep to force tkinter to update all GUIs. Commented May 31 at 12:08

1 Answer 1

1

There are two methods:

  1. use root.update() to force tkinter to update widgets before end of function
def bonk():
    global count

    print("bonked")
    count += 1
    counter.config(text=f"Bonk counter: {count}")
    
    if count < 5:
        BONK.config(state="disabled")
        picture.config(image=Bonk2)

        root.update()  # force tkinter to update widgets before end of function

        time.sleep(2) #delay

        picture.config(image=Bonk1) #Changing back the image
        BONK.config(state="active")
    else:
        picture.config(image=Bonk4)
        BONK.config(state="disabled")
  1. use root.after(milliseconds, function_name) (instead of sleep) to execute some code later - and tkinter will finnish current function and it will update widgets
def bonk():
    global count

    print("bonked")
    count += 1
    counter.config(text=f"Bonk counter: {count}")
    
    if count < 5:
        BONK.config(state="disabled")
        picture.config(image=Bonk2)

        root.after(2000, other_function)  # execute some code later

    else:
        picture.config(image=Bonk4)
        BONK.config(state="disabled")

def other_fucntion():
    picture.config(image=Bonk1) #Changing back the image
    BONK.config(state="active")
Sign up to request clarification or add additional context in comments.

2 Comments

I would recommend avoiding sleep in a GUI application at all costs (at least in the main thread) because the GUI will necessarily hang for the duration of the sleep. Using after is best practice.
@jriggles I agree, in most situations sleep makes only problem in any GUI :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.