【问题标题】:Speeding up potentially long tasks加速可能较长的任务
【发布时间】:2017-12-16 23:51:20
【问题描述】:

我决定创建一个在 Tkinter 中轻松显示动画 gif 的类,它确实有效,但动态收集所有帧的过程几乎总是需要大量时间,并且在完成之前阻止其他任何事情发生。我想知道是否有任何方法可以加快速度或更有效的方式来做同样的事情。

这是该类的代码:

from tkinter import *

class animation:
    def __init__(self,*args,**kwargs):
        self.root=args[0]
        self.label=Label(self.root)
        self.label.grid()
        self.image=kwargs["image"]
        try:
            self.delay=kwargs["delay"]
        except KeyError:
            self.delay=20

        self.frames=[]
        x=0
        while True:
            try:
                img=PhotoImage(file=self.image,
                               format="gif -index {}".format(x))
                self.frames.append(img)
                x+=1
            except:
                break


    def animate(self,y):
        try:
            self.label.configure(image=self.frames[y])
            self.root.after(self.delay,lambda:self.animate(y+1))
        except IndexError:
            self.label.configure(image=self.frames[0])
            self.root.after(self.delay,lambda:self.animate(1))

下面是它的使用方法:

from tkinter import *
from modules.animation import animation

root=Tk()

cosmog=animation(root,image="cosmog.gif").animate(0)
cosmoem=animation(root,image="cosmoem.gif").animate(0)
lunala=animation(root,image="lunala.gif").animate(0)

root.mainloop()

【问题讨论】:

  • 也许在你启动 tkinter 之前创建一个读取所有图像的类。或者使用线程读取文件。
  • 它不会有太大帮助,但是您应该加载一次图像,然后将所有帧拉出,而不是从 HDD 为每一帧加载图像。 Here's how I did that。另外,请注意创建 tkinter 小部件的正确方法:通过子类化当前小部件。这样,您就可以将其视为代码中的任何其他小部件(pack、grid、tkraise 等)。
  • FWIW,您可以使用 self.root.after(self.delay,lambda:self.animate(1)) 而不是 self.root.after(self.delay, self.animate, 1)
  • 感谢大家的帮助

标签: python tkinter


【解决方案1】:

用线程尝试这样:

import threading
import time

def __init__(self, *args, **kwargs):
    self.frames=[]
    self.run_loop = True
    self.x=0
    self.taken = []
    self.order = []

    while self.run_loop:
        threading.Thread(target=self.add_image).start()

def add_image(self):
    try:
        if self.x not in self.taken: # make sure not several threads add the same image index
            self.taken.append(self.x)
            self.x+=1
        else:
           return

        # save local x before creating image, for the order
        # all the other threads will increment self.x while Image is created
        x = self.x   

        img=PhotoImage(file=self.image, format="gif -index {}".format(self.x))

        self.frames.append(img)
        self.order.append(x) # keep track of the order

        if len(self.frames) == len(self.taken): # when finish
            self.frames = [x for _,x in sorted(zip(self.order,self.frames))]  # sort the frames to the order

    except:
        self.run_loop = False

我做了一个没有 tkinter 的简单可运行示例,使用 time.sleep(随机时间量)来模拟 PhotoImage:

import threading
import time
from random import randint

class Test:

    frames=[]
    run_loop = True
    x=0
    taken = []
    order = []
    time = 0

    def __init__(self):
        while self.run_loop:
            threading.Thread(target=self.add_image).start()

    def add_image(self):
        if self.x < 100:
            if self.x not in self.taken: # make sure not several threads add the same image index
                self.taken.append(self.x)
                self.x+=1
            else:
               return

            x = self.x
            t = randint(1,10)/10.0
            self.time += t

            time.sleep(t) # PhotoImage random time.sleep 0 to 1 second

            self.order.append(x)
            self.frames.append(x)

            if len(self.frames) == len(self.taken):
                print("Frames before sort")
                print(self.frames)

                self.frames = [x for _,x in sorted(zip(self.order,self.frames))]

                print("\nFrames after sort")
                print(self.frames)

                print("\nTime used combined: {} seconds".format(self.time))


        else:
            self.run_loop = False


t = Test()

此测试显示使用的总时间约为 50 秒。
使用 100 个线程,它可以在 1 秒内完成。最长 time.sleep 的时间量,即 0 到 1 秒。
所以对你来说,它不应该超过一个最长的PhotoImage 电话

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-15
    相关资源
    最近更新 更多