具有无限循环的 Tkinter 退出命令
Tkinter exit command with infinite loop
我在使用 tkinter window 界面的关闭按钮时遇到一些问题。我的工具实时显示一些视频,我用 after 函数无限循环来实现。
当我通过单击十字关闭 tkinter window 时,程序冻结。但是,当我单击该按钮时,将调用相同的函数但它会正确关闭。
这是我想出的最简化的代码来向您展示问题。谁有解释和解决方法吗?
(顺便说一句,我在 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 中重新创建它,并添加拖动 window 使用:Python/Tkinter: Mouse drag a window without borders, eg. overridedirect(1)
编辑(08/20): 其实我连window都拖不动。工具也冻死了!
您可能只需要终止动画循环。 after
returns 可用于取消挂起作业的作业 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 变慢。
我找到了一个解决方案,我不确定它是否真的干净,但至少它可以满足我的需求。我不再使用 after 但我在每次迭代时循环并更新 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()
我在使用 tkinter window 界面的关闭按钮时遇到一些问题。我的工具实时显示一些视频,我用 after 函数无限循环来实现。
当我通过单击十字关闭 tkinter window 时,程序冻结。但是,当我单击该按钮时,将调用相同的函数但它会正确关闭。
这是我想出的最简化的代码来向您展示问题。谁有解释和解决方法吗?
(顺便说一句,我在 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 中重新创建它,并添加拖动 window 使用:Python/Tkinter: Mouse drag a window without borders, eg. overridedirect(1)
编辑(08/20): 其实我连window都拖不动。工具也冻死了!
您可能只需要终止动画循环。 after
returns 可用于取消挂起作业的作业 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 变慢。
我找到了一个解决方案,我不确定它是否真的干净,但至少它可以满足我的需求。我不再使用 after 但我在每次迭代时循环并更新 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()