You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter窗口GIF动图无法播放的解决求助

解决Tkinter中GIF动图无法自动播放的问题

你的代码仅加载了GIF的第一帧,未处理多帧切换逻辑,因此无法自动播放。要实现GIF持续循环播放,需要提取GIF的所有帧,并用Tkinter的after()方法定时更新Label的图像。以下是修改后的完整代码:

import tkinter as tk
from PIL import Image, ImageTk

root = tk.Tk()
root.title("Main Window")
root.geometry('300x400')

def open_second_window():
    second_window = tk.Toplevel(root)
    second_window.title("menu")
    second_window.geometry('700x700')

    image_path = "menu.png"
    image = Image.open(image_path)
    photo = ImageTk.PhotoImage(image)

    label = tk.Label(second_window, image=photo)
    label.image = photo  
    label.pack(fill=tk.BOTH, expand=True)
    label.place(x=0, y=0)

    button = tk.Button(second_window, height=4, width=12, font='Times 31', wraplength=289, 
                       text="First gif", command=open_firstgif_window)
    button.place(x=308, y=302, anchor='ne')
    
    button1 = tk.Button(second_window, height=4, width=12, font='Times 31', wraplength=289, 
                        text="Second gif", command=open_secondgif_window)
    button1.place(x=688, y=302, anchor='ne')

def play_gif(window, label, frames):
    def update_frame(frame_idx):
        # 更新当前显示的帧
        current_frame = frames[frame_idx]
        label.config(image=current_frame)
        label.image = current_frame  # 保留引用,避免被垃圾回收机制销毁
        # 计算下一帧索引,实现循环播放
        next_idx = (frame_idx + 1) % len(frames)
        # 按GIF原有的帧间隔切换下一帧
        window.after(frames[0].info['duration'], update_frame, next_idx)
    # 启动播放
    update_frame(0)

def open_firstgif_window():
    firstgif_window = tk.Toplevel(root)
    firstgif_window.title("first_gif")
    firstgif_window.geometry('700x700')

    image_path = "road-sign-roadtrip.gif"
    image = Image.open(image_path)
    # 提取GIF的所有帧
    frames = []
    try:
        while True:
            frames.append(ImageTk.PhotoImage(image.copy()))
            image.seek(len(frames))  # 跳转到下一帧
    except EOFError:
        pass  # 所有帧读取完毕

    label = tk.Label(firstgif_window)
    label.pack(fill=tk.BOTH, expand=True)
    label.place(x=0, y=0)

    # 启动GIF播放
    play_gif(firstgif_window, label, frames)

    tk.Label(firstgif_window, font='Times 30', text="first gif", fg="red").place(x=150, y=30)

    button = tk.Button(firstgif_window, height=4, width=12, font='Times 31', 
                       text="Exit", command=Close)
    button.place(x=308, y=302, anchor='ne')

def open_secondgif_window():
    secondgif_window = tk.Toplevel(root)
    secondgif_window.title("second_gif")
    secondgif_window.geometry('700x700')

    image_path = "road-sign-roadtrip.gif"
    image = Image.open(image_path)
    # 提取GIF的所有帧
    frames = []
    try:
        while True:
            frames.append(ImageTk.PhotoImage(image.copy()))
            image.seek(len(frames))  # 跳转到下一帧
    except EOFError:
        pass  # 所有帧读取完毕

    label = tk.Label(secondgif_window)
    label.pack(fill=tk.BOTH, expand=True)
    label.place(x=0, y=0)

    # 启动GIF播放
    play_gif(secondgif_window, label, frames)

    tk.Label(secondgif_window, font='Times 30', text="Second gif", fg="red").place(x=150, y=30)

    button = tk.Button(secondgif_window, height=4, width=12, font='Times 31', 
                       text="Exit", command=Close)
    button.place(x=308, y=302, anchor='ne')

def Close(): 
    root.destroy() 

button = tk.Button(root, text="Open Second Window", command=open_second_window)
button.pack()

root.mainloop()

关键修改说明

  • 提取所有帧:通过循环调用image.seek()读取GIF的每一帧,直到抛出EOFError表示所有帧读取完成,将每帧转换为ImageTk.PhotoImage存入列表。
  • 定时切换帧:封装play_gif函数,用window.after()按照GIF原有的帧间隔(image.info['duration'],单位毫秒)定时更新Label的图像,实现循环播放。
  • 保留图像引用:每次更新帧时,将当前帧赋值给label.image,避免Python垃圾回收机制销毁图像对象导致显示异常。
  • 修正拼写错误:修复了原代码中函数名的拼写错误(如open_firtsgif_window改为open_firstgif_window)。

内容的提问来源于stack exchange,提问作者kot may

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 22:09:57