I just started a week ago learning Python and currently I am learning Tkinter. I wanted to programm a TicTacToe game that opens another GUI which plays a Gif every time someone wins. TicTacToe works, although it might need a few more lines of code to be perfect. I can open another GUI via root1 = tk.Toplayer() which is supposed to play the Gif. When it opens it plays the Gif, but only once. Is it possible to make it an actual looped Gif?
Here my code:
import tkinter as tk
from PIL import Image, ImageTk, ImageSequence
import time
clicked = True
count = 0
winner = False
def b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9):
global winner
winner = False
if b1["bg"] == "red" and b2["bg"] == "red" and b3["bg"] == "red":
print("sieg")
winner = True
win()
elif b4["bg"] == "red" and b5["bg"] == "red" and b6["bg"] == "red":
winner = True
winner = True
win()
elif b7["bg"] == "red" and b8["bg"] == "red" and b9["bg"] == "red":
winner = True
winner = True
win()
elif b1["bg"] == "red" and b4["bg"] == "red" and b7["bg"] == "red":
winner = True
winner = True
win()
elif b2["bg"] == "red" and b5["bg"] == "red" and b8["bg"] == "red":
winner = True
winner = True
win(play_gif())
elif b3["bg"] == "red" and b6["bg"] == "red" and b9["bg"] == "red":
winner = True
winner = True
win()
elif b1["bg"] == "red" and b5["bg"] == "red" and b9["bg"] == "red":
winner = True
winner = True
win()
elif b3["bg"] == "red" and b5["bg"] == "red" and b7["bg"] == "red":
winner = True
winner = True
win()
elif b1["bg"] == "green" and b2["bg"] == "green" and b3["bg"] == "green":
winner = True
winner = True
win()
elif b4["bg"] == "green" and b5["bg"] == "green" and b6["bg"] == "green":
winner = True
winner = True
win()
elif b7["bg"] == "green" and b8["bg"] == "green" and b9["bg"] == "green":
winner = True
winner = True
win()
elif b1["bg"] == "green" and b4["bg"] == "green" and b7["bg"] == "green":
winner = True
winner = True
win()
elif b2["bg"] == "green" and b5["bg"] == "green" and b8["bg"] == "green":
winner = True
winner = True
win()
elif b3["bg"] == "green" and b6["bg"] == "green" and b9["bg"] == "green":
winner = True
winner = True
win()
elif b1["bg"] == "green" and b5["bg"] == "green" and b9["bg"] == "green":
winner = True
winner = True
win()
elif b3["bg"] == "green" and b5["bg"] == "green" and b7["bg"] == "green":
winner = True
winner = True
win()
def b_switch(b):
global clicked, count
if b["state"] == "normal" and clicked == True:
b["bg"] = "red"
b["state"] = "disabled"
clicked = False
count = 1
elif b["state"] == "normal" and clicked == False:
b["bg"] = "green"
b["state"] = "disabled"
clicked = True
count = 1
def b_reset(root):
root.destroy()
mainWindow()
def mainWindow():
root = tk.Tk()
root.title("TicTacToe")
root.geometry("400x410")
root.resizable(False, False)
b0 = tk.Button(root, text="reset", height=1, width=50, command=lambda: [b_reset(root)])
b0.pack()
b1 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b1), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b1.place(x=10, y=30)
b2 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b2), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b2.place(x=140, y=30)
b3 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b3), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b3.place(x=270, y=30)
b4 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b4), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b4.place(x=10, y=160)
b5 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b5), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b5.place(x=140, y=160)
b6 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b6), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b6.place(x=270, y=160)
b7 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b7), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b7.place(x=10, y=290)
b8 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b8), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b8.place(x=140, y=290)
b9 = tk.Button(root, width=15, height=7, command=lambda: [b_switch(b9), b_check(b1, b2, b3, b4, b5, b6, b7, b8, b9),
])
b9.place(x=270, y=290)
root.mainloop()
def win():
if winner == True:
root1 = tk.Toplevel()
root1.resizable(False, False)
root1.title("Winner")
global img
img = Image.open("capybara-ok-i-pull-up.gif")
label = tk.Label(root1)
label.place(x=0, y=0)
play_gif(root1, img, label)
def play_gif(root1, img, label):
while winner == True:
for img in ImageSequence.Iterator(img):
img = img.resize((300,300))
img = ImageTk.PhotoImage(img)
label.config(image=img)
root1.update()
time.sleep(0.01)
root1.after(0, play_gif(root1, img, label))
mainWindow()
I tried using just a 2nd GUI which was root1 = tk.Tk() which didnt play the Gif since apparently Tkinter doesnt like it if another GUI is opened. Then I came across the Toplayer command but now I am stuck with the problem stated above.
CodePudding user response:
If you want to loop the images inside a GIF, you can use itertools.cycle()
to create a cycle list of images and use next()
to get the next image in the cycle list.
Below is the modified play_gif()
and win()
:
from itertools import cycle
import tkinter as tk
from PIL import Image, ImageTk, ImageSequence
...
def play_gif(imagelist, label):
img = next(imagelist) # get next image in the list
img = img.resize((300, 300))
label.img = ImageTk.PhotoImage(img)
label.config(image=label.img)
label.after(50, play_gif, imagelist, label)
def win():
# create a cycle list of images from a GIF image
with Image.open("capybara-ok-i-pull-up.gif") as im:
imagelist = cycle(ImageSequence.all_frames(im))
root1 = tk.Toplevel()
root1.resizable(0, 0)
root1.title("Winner")
label = tk.Label(root1)
label.pack()
# start the image animation
play_gif(imagelist, label)
...