Chr*_*ung 4 python multithreading label tkinter
我有以下Python Tkinter代码,它每10秒重绘一次标签.我的问题是,对我而言似乎是在旧标签上一遍又一遍地绘制新标签.因此,最终,几个小时后将有数百个绘图重叠(至少从我的理解).这会占用更多内存还是会导致问题?
import Tkinter as tk
import threading
def Draw():
frame=tk.Frame(root,width=100,height=100,relief='solid',bd=1)
frame.place(x=10,y=10)
text=tk.Label(frame,text='HELLO')
text.pack()
def Refresher():
print 'refreshing'
Draw()
threading.Timer(10, Refresher).start()
root=tk.Tk()
Refresher()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
在我的例子中,我只使用一个标签.我知道我可以使用textvariable更新标签的文本甚至text.config.但实际上做的是刷新标签网格(如表格)+按钮和内容以匹配可用的最新数据.
从我的初学者的理解,如果我把这个Draw()函数写成类,我可以frame通过使用frame.destroy每当我执行Refresher函数来销毁它.但是我目前拥有的代码是在没有类的函数中编写的(我不希望将整个代码重写为类).
我能想到的另一个选择是frame在Draw()全局和使用中声明frame.destroy()(我不愿意这样做,因为如果我有太多帧(这样做),这可能会导致名称冲突)
如果对旧图纸进行透支不会导致任何问题(除了我看不到旧图纸),我可以忍受.
这些都只是我初学者的想法.我应该在重绘更新的帧之前销毁帧吗?如果是这样,如果代码结构就像我的示例代码一样,我应该以什么方式销毁它?或透支旧标签是好的?
编辑
有人提到python tkinter不是线程安全的,我的代码可能会随机失败.
我实际上把这个链接作为参考使用threading作为我的解决方案,我没有找到任何关于该帖子中的线程安全性.
我想知道我不应该使用的一般情况是threading什么,我可以使用的一般情况是什么threading?
Bry*_*ley 11
在tkinter中运行函数或更新标签的正确方法是使用after方法.这会将事件队列中的事件放在将来的某个时间执行.如果你有一个功能可以做一些工作,然后把自己放回事件队列,你已经创建了一些将永远运行的东西.
以下是基于您的示例的简单示例:
import Tkinter as tk
import time
def Draw():
global text
frame=tk.Frame(root,width=100,height=100,relief='solid',bd=1)
frame.place(x=10,y=10)
text=tk.Label(frame,text='HELLO')
text.pack()
def Refresher():
global text
text.configure(text=time.asctime())
root.after(1000, Refresher) # every second...
root=tk.Tk()
Draw()
Refresher()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
从编码风格的角度来看,我会对这个程序进行很多改变,但我希望尽可能地保持它与原始问题的接近程度.关键是,您可以使用after调用更新标签的函数而无需创建新标签.另外,该功能可以安排自己在某个时间间隔再次调用.在这个例子中,我选择了一秒钟,以便更容易看到效果.
你还问"我想知道我不应该使用线程的一般情况是什么,我可以使用线程的一般情况是什么?"
如果你不得不问一个关于何时使用线程的问题,那么你就不应该使用线程.线程是一种先进的技术,它很复杂,容易出错.线程很可能使程序变慢而不是更快.它会产生微妙的后果,例如,如果你做的事情不是线程安全的,你的程序就会神秘地失败.
更具体地说明你的情况:你应该避免使用带有tkinter的线程.您可以使用它们,但不能从这些其他线程访问小部件.如果需要对窗口小部件执行某些操作,则必须将指令放在线程安全的队列中,然后在主线程中需要定期检查该队列以查看是否有要处理的指令.如果您搜索它们,可以在本网站上找到相关示例.
如果这听起来很复杂,那就是.对于您编写的大多数GUI,您无需担心这一点.如果您可以将大型进程分解为在100毫秒或更短时间内执行的块,那么您只需要after并且永远不需要线程.
要允许使用最少的代码更改进行清理,您可以显式传递先前的帧:
import Tkinter as tk
def Draw(oldframe=None):
frame = tk.Frame(root,width=100,height=100,relief='solid',bd=1)
frame.place(x=10,y=10)
tk.Label(frame, text='HELLO').pack()
frame.pack()
if oldframe is not None:
oldframe.destroy() # cleanup
return frame
def Refresher(frame=None):
print 'refreshing'
frame = Draw(frame)
frame.after(10000, Refresher, frame) # refresh in 10 seconds
root = tk.Tk()
Refresher()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13379 次 |
| 最近记录: |