3

So, as I'm sure you can tell from my rather long subject what I'm asking but to reiterate. I am trying to have a gif animate while a thread in the background is running a calculation with in TKinter. For simplicities sake, I am using this gif: http://i.imgur.com/4Y9UJ.gif

The gif animation is currently working as you can see if you run the script. But as soon as the Generate button is pressed and the thread initiates, the gif pauses until it finishes. I'm using time.sleep() to simulate the large amount of calculations that I will be doing in the background (though I am unsure if this is what is actually causing the issue).

I'm sure it has something to do with not understanding exactly how the animation is functioning. Any advice?

Code as follows:

from Tkinter import *
import tkMessageBox
import time
import os
import threading
from PIL import Image, ImageTk

class Gif(Label):
    def __init__(self, master, filename):
        evanGif = Image.open(filename)
        gifSeq = []
        try:
            while 1:
                gifSeq.append(evanGif.copy())
                evanGif.seek(len(gifSeq)) # skip to next frame
        except EOFError:
            pass # we're done
        try:
            #Special case for the evangalion gif
            if evanGif.info['duration'] == 0:
                self.delay = 100
            else:
                self.delay = evanGif.info['duration']
        except KeyError:
            self.delay = 100
        gifFirst =gifSeq[0].convert('RGBA')
        self.gifFrames = [ImageTk.PhotoImage(gifFirst)]

        Label.__init__(self, master, image=self.gifFrames[0])

        temp =gifSeq[0]
        for image in gifSeq[1:]:
            temp.paste(image)
            frame = temp.convert('RGBA')
            self.gifFrames.append(ImageTk.PhotoImage(frame))

        self.gifIdx = 0
        self.cancel = self.after(self.delay, self.play)

    def play(self):
        self.config(image=self.gifFrames[self.gifIdx])
        self.gifIdx += 1
        if self.gifIdx == len(self.gifFrames):
            self.gifIdx = 0
        self.cancel = self.after(self.delay, self.play)

class App:
    generating = False
    def __init__(self, master):
        self.master=master

        #Initializing frames
        self.buttonFrame = Frame(master, background='light gray')
        self.loadingFrame = Frame(master, background='light gray')
        self.loadingFrame.grid(row=0)
        self.buttonFrame.grid(row=1)
        self.anim = Gif(self.loadingFrame, '4Y9UJ.gif').pack()
        self.update_Thread = threading.Thread(target=time.sleep, args=(5,))
        self.buttonSetup()

    def buttonSetup(self):
        #ALL THE BUTTONS
        self.generateBt = Button(self.buttonFrame, text="Generate!", command=self.generate, background='light gray', highlightbackground='light gray')
        self.generateBt.pack(side=LEFT)
        self.quitBt = Button(self.buttonFrame, text="Quit!", fg="red", command=self.buttonFrame.quit, background='light gray', highlightbackground='light gray')
        self.quitBt.pack(side=LEFT)

    def generate(self):
        self.hideForGen()
        self.update_Thread.start()
        while(self.update_Thread.isAlive()):
            self.master.update_idletasks()
        self.reset()
        self.master.update_idletasks()
        tkMessageBox.showinfo("Complete", "Report generation completed!")

    def hideForGen(self):
        self.buttonFrame.grid_forget()

    def reset(self):
        self.buttonFrame.grid(row=1)

root = Tk()
root.title('Test')
root.configure(background='light gray')
app = App(root)
root.mainloop()
4

2 回答 2

1

问题在于您的 generate() 方法。那个while循环是不必要的。

请记住,您无法重新启动线程。如果您想多次使用生成按钮,则每次都需要创建一个新线程。

class App:
    generating = False
    def __init__(self, master):
        self.master=master

        #Initializing frames
        self.buttonFrame = Frame(master, background='light gray')
        self.loadingFrame = Frame(master, background='light gray')
        self.loadingFrame.grid(row=0)
        self.buttonFrame.grid(row=1)
        self.anim = Gif(self.loadingFrame, '4Y9UJ.gif')
        self.anim.pack()
##        self.update_Thread = threading.Thread(target=time.sleep, args=(5,))

        self.buttonSetup()

    def buttonSetup(self):
        #ALL THE BUTTONS
        self.generateBt = Button(self.buttonFrame, text="Generate!", command=self.generate, background='light gray', highlightbackground='light gray')
        self.generateBt.pack(side=LEFT)
        self.quitBt = Button(self.buttonFrame, text="Quit!", fg="red", command=self.buttonFrame.quit, background='light gray', highlightbackground='light gray')
        self.quitBt.pack(side=LEFT)

    def wait_generate(self):
        if self.update_Thread.isAlive():
            self.master.after(500, self.wait_generate)
        else:
            tkMessageBox.showinfo("Complete", "Report generation completed!")
            self.reset()

    def generate(self):
        self.hideForGen()
        self.update_Thread = threading.Thread(target=time.sleep, args=(5,))
        self.update_Thread.start()
##        while(self.update_Thread.isAlive()):
##            self.master.update_idletasks()
##        self.reset()
##        self.master.update_idletasks()
##        tkMessageBox.showinfo("Complete", "Report generation completed!")
        self.wait_generate()

    def hideForGen(self):
        self.buttonFrame.grid_forget()

    def reset(self):
        self.buttonFrame.grid(row=1)
于 2012-07-17T22:26:18.093 回答
1

在下面的方法中:

    def generate(self):
        self.hideForGen()
        self.update_Thread.start()
        while(self.update_Thread.isAlive()):
            self.master.update_idletasks()
        self.reset()
        self.master.update_idletasks()
        tkMessageBox.showinfo("Complete", "Report generation completed!")

如果你把

    self.master.update()

代替

    self.master.update_idletasks()

它应该工作。至少它对我有用。

于 2012-07-17T11:37:20.013 回答