Reputation: 55
My code:
from tkinter import *
import random
from PIL import ImageTk, Image
import time
class App():
def __init__(self, root, dice_image):
self.dice_label = Label(root, image=dice_image)
self.dice_label.pack()
self.button = Button(root, text="Roll", font=("Fixedsys", 25) , width=20, height=20, bg="red" , command=rolling)
self.button.pack(pady=70)
I want to make the image change fast to make it look like rolling. But I don't know why it change nothing before the for loop end.
def rolling():
global dices
for i in range(1, 10 + 1):
time.sleep(0.3)
random.shuffle(dices)
app.dice_label.configure(image=dices[0])
if __name__ == '__main__':
root = Tk()
root.geometry("800x600")
# Var
dice_image = ImageTk.PhotoImage(Image.open("Dices.jpg"))
dice1 = ImageTk.PhotoImage(Image.open("Dice1.jpg"))
dice2 = ImageTk.PhotoImage(Image.open("Dice2.jpg"))
dice3 = ImageTk.PhotoImage(Image.open("Dice3.jpg"))
dice4 = ImageTk.PhotoImage(Image.open("Dice4.jpg"))
dice5 = ImageTk.PhotoImage(Image.open("Dice5.jpg"))
dice6 = ImageTk.PhotoImage(Image.open("Dice6.jpg"))
dices = [dice1, dice2, dice3, dice4, dice5, dice6]
app = App(root, dice_image)
root.mainloop()
Upvotes: 0
Views: 65
Reputation: 15226
Tkinter and sleep()
are not friends. The problem is that Tkinter functions inside of a mainloop and sleep pauses that loop until all the sleep time is over.
This will always freeze your application.
Try using after()
and a refactored function instead.
I have not tested this but I believe something like this should fix your problem or at least get rid of the problem that sleep()
will cause.
I have changed your button command to send a call to the function using lambda
so that the call wont go out at runtime but only when pressing the button.
from tkinter import *
import random
from PIL import ImageTk, Image
class App():
def __init__(self, root, dice_image):
self.dice_label = Label(root, image=dice_image)
self.dice_label.pack()
self.button = Button(root, text="Roll", font=("Fixedsys", 25),
width=20, height=20, bg="red" ,
command=lambda: rolling(1,11))
self.button.pack(pady=70)
I have updated your rolling function to handly a timed loop.
root.after(300, lambda: rolling(stop, counter))
will call the function it is in only if the counter has not finished counting down and only once every 0.3 seconds. Again lambda is used here to make sure the call to rolling does not happen at runtime.
def rolling(s, e, start=False):
global dices
counter = 0
stop = 0
if start:
counter = s
stop = e
if counter > stop:
random.shuffle(dices)
app.dice_label.configure(image=dices[0])
counter -= 1
root.after(300, lambda: rolling(stop, counter))
I have also updated this portion to use a loop so you don't have to repeat yourself when crating a list of images.
if __name__ == '__main__':
root = Tk()
root.geometry("800x600")
dice_image = ImageTk.PhotoImage(Image.open("Dices.jpg"))
dices = []
for i in range(6):
dices.append(ImageTk.PhotoImage(Image.open(f"Dice{i+1}.jpg")))
app = App(root, dice_image)
root.mainloop()
Upvotes: 2