Home > Software design >  Is there a way to open another GUI in Tkinter that plays a Gif, whilst the main GUI is still active
Is there a way to open another GUI in Tkinter that plays a Gif, whilst the main GUI is still active

Time:11-18

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)

...
  • Related