带有无限循环的Tkinter退出命令

时间:2015-08-14 16:20:06

标签: python tkinter tk

我在使用tkinter的界面窗口的关闭按钮时遇到了一些问题。我的工具实时显示一些视频,我使用after函数进行无限循环。

当我通过点击十字架关闭tkinter窗口时,程序会冻结。但是,当我单击按钮时,会调用相同的函数,但它会正常关闭。

这是我出现的最简单的代码,向您展示问题。有没有人有解释和解决方法?

(顺便说一下,我在OSX上使用Python 2.7.8)

from Tkinter import *
from PIL import Image, ImageTk
import numpy as np

class Test():
    def __init__(self, master):
        self.parent = master
        self.frame = Frame(self.parent)
        self.frame.pack(fill=BOTH, expand=1)
        self.mainPanel = Label(self.frame)
        self.mainPanel.pack(fill=BOTH, expand=1)
        self.closeButton = Button(self.frame, command=self.closeApp)
        self.closeButton.pack(fill=BOTH, expand=1)

    def closeApp(self):
        print "OVER"
        self.parent.destroy()

def task(tool):
    print 'ok'
    im = Image.fromarray(np.zeros((500, 500, 3)), 'RGB')
    tool.tkim = ImageTk.PhotoImage(im)
    tool.mainPanel['image'] = tool.tkim
    root.after(1, task, tool)

def on_closing():
    print "OVER"
    root.destroy()

root = Tk()
root.wm_protocol("WM_DELETE_WINDOW", on_closing)
tool = Test(root)
root.after(1, task, tool)
root.mainloop()

现在,如果您再次尝试使用较小的图像(例如100 * 100),它就能正常工作。或者如果你在after函数中延迟100,它也可以。但在我的应用程序中,我需要一个非常短的延迟时间,因为我正在显示一个视频,我的图像大小是900px * 500px。

谢谢!

编辑(08/19):我还没有找到解决方案。但我可以使用root.overrideredirect(1)删除关闭按钮,然后在Tk中重新创建它,并使用以下内容添加拖动窗口:Python/Tkinter: Mouse drag a window without borders, eg. overridedirect(1)

编辑(08/20):实际上,我甚至无法拖动窗口。该工具也冻结了!

2 个答案:

答案 0 :(得分:2)

你可能只需要杀死你的动画循环。 after返回一个可用于取消待处理作业的作业ID。

def task():
    global job_id
    ...
    job_id = root.after(1, task, tool)

def on_closing():
    global job_id
    ...
    root.after_cancel(job_id)

如果这些函数是对象的方法,那么您的代码可能会更清晰,因此您不必使用全局变量。此外,您应该有一个退出功能而不是两个。或者,让一个人调用另一个,这样你就可以确定两个代码路径完全相同。

最后,除非你真的需要,否则你不应该每秒1000次调用一个函数。经常调用它会使你的UI变得迟钝。

答案 1 :(得分:1)

我找到了一个解决方案,我不确定它是否真的很干净,但至少它适用于我想做的事情。我不再使用,但我在每次迭代时循环并更新gui。

from Tkinter import *
from PIL import Image, ImageTk
import numpy as np


class Test():
    def __init__(self, master):
        self.parent = master
        self.frame = Frame(self.parent)
        self.frame.pack(fill=BOTH, expand=1)
        self.mainPanel = Label(self.frame)
        self.mainPanel.pack(fill=BOTH, expand=1)
        self.parent.wm_protocol("WM_DELETE_WINDOW", self.on_closing)
        self.close = 0

    def on_closing(self):
        print "Over"
        self.close = 1

    def task(self):
        print "ok"
        im = Image.fromarray(np.zeros((500, 500, 3)), 'RGB')
        self.tkim = ImageTk.PhotoImage(im)
        self.mainPanel['image'] = self.tkim

root = Tk()
tool = Test(root)

while(tool.close != 1):
    tool.task()
    root.update()
root.destroy()