Tkinter动画将变得无响应并崩溃,除非调用根目录更新()每帧

2024-04-26 07:55:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我试着在窗口上播放一些简单的动画。这是我第一次使用Tkinter,所以我给根目录更新()以确保它显示在屏幕上(否则帧速率有点不稳定)。我现在了解到这是一种非常糟糕的做法,并试图将其完全删除,或者用调用根目录更新\u idletasks(). 奇怪的是,当我这么做的时候,窗户会变得毫无反应,最终会崩溃。你知道吗

我尝试将代码剥离到最低限度(如下所示),但问题仍然存在。你知道吗

from tkinter import *
from tkinter import ttk
from PIL import ImageTk, Image

class Application():
    def __init__(self):
        # WINDOW SETUP
        self.root = Tk()
        self.root.geometry('512x512')
        self.root.protocol('WM_DELETE_WINDOW', self.Annihilation)

        self.screen = ttk.Label(self.root)
        self.screen.place(relx=.5, rely=.5, anchor="c")

        # CALL THE ANIMATION FUNCTION
        self.state = 'Idle'
        self.Animation(self.state, [self.Idle1, self.Idle2], 500)

        self.root.mainloop()


    # ANIMATION FUNCTION
    def Animation(self, State, framelist, frameduration):
        for i in range(len(framelist)):
            if self.state == State:
                frame = framelist[i]()
                self.screen.configure(image = frame)
                self.root.update() # THIS IS THE LINE I WANT TO REMOVE
                self.root.after(frameduration)          
            else:
                return

        self.Animation(State, framelist, frameduration)

    # LIST OF IMAGES
    def Idle1(self):
        return ImageTk.PhotoImage(Image.open('Image1.tif').resize((512, 512)))
    def Idle2(self):
        return ImageTk.PhotoImage(Image.open('Image2.tif').resize((512, 512)))


    def Annihilation(self):
        self.root.eval('::ttk::CancelRepeat')
        self.state = 'Quitting'
        self.root.destroy()

Application()

这闻起来像是“你的代码中有一个更大的错误,你的第一个错误是不小心被挡在了海湾里”,但我已经没有主意了,我还没能用谷歌搜索这个。任何帮助都将不胜感激。你知道吗


Tags: fromimageimportselfreturndefrootscreen
1条回答
网友
1楼 · 发布于 2024-04-26 07:55:28

您不应该使用for循环,因为它可能需要一些时间,并且在帧之间没有时间就没有意义。不要在Animation中运行Animation,因为它会创建您不需要的递归。使用after(time, Animation)

我使用self.current_frame来保存要显示哪个帧的信息。Animation只显示一个帧,更改self.current_frame中的值并使用after()再次运行它—它将替换for循环。它还取代了递归。你知道吗

也可以只加载一次图像,并将图像保留在列表中,而不是函数名 从tkinter导入* 从tkinter导入ttk 从PIL导入ImageTk,Image

class Application():

    def __init__(self):

        # WINDOW SETUP
        self.root = Tk()
        self.root.geometry('512x512')
        self.root.protocol('WM_DELETE_WINDOW', self.annihilation)

        self.screen = ttk.Label(self.root)
        self.screen.place(relx=.5, rely=.5, anchor="c")

        # CALL THE ANIMATION FUNCTION
        self.state = 'Idle'

        self.current_frame = 0
        self.animation(self.state, [self.idle1, self.idle2], 500)

        self.root.mainloop()


    # ANIMATION FUNCTION
    def animation(self, State, framelist, frameduration):
        if state == self.state:
            # change image
            self.frame = framelist[self.current_frame]()
            self.screen.configure(image=self.frame)

            # get next frame (or first frame)
            self.current_frame = (self.current_frame+1) % len(framelist)

        # run again after 'frameduration' milliseconds
        self.root.after(frameduration, self.animation, State, framelist, frameduration)


    # LIST OF IMAGES
    def idle1(self):
        return ImageTk.PhotoImage(Image.open('Image1.tif').resize((512, 512)))

    def idle2(self):
        return ImageTk.PhotoImage(Image.open('Image2.tif').resize((512, 512)))


    def annihilation(self):
        self.root.eval('::ttk::CancelRepeat')
        self.state = 'Quitting'
        self.root.destroy()

Application()

因为PEP 8 Style Guide for Python Code,我把名字改成小写

相关问题 更多 >