比方说,我们有3个tkinter小部件:标签,树视图和Optionmenu(以下简称为“ menu”)。一旦选择了选项,我就使菜单成功执行了功能。简短的函数如下所示:
def data_process():
# do something takes time
def print_data()
data_process() # do something takes time too
# print stuff to treeview
def refresh_table(self, args):
label['text'] = 'Executing' # change label text to Executing
print_data() # a func. which takes time to run
label['text'] = 'Done' # change text to Done
label = tk.Label(parent, text = 'ready')
label.pack()
menu = tk.OptionMenu(parent, var, *list, command = lambda _:refresh_table(self, args))
menu.pack()
table = tk.Treeview(parent)
table.pack()
函数print_data
将要打印一些内容到树形视图小部件(表)。标签小部件就像一个状态栏,告诉用户现在正在发生什么。因此,我尝试执行的工作流程是:
在菜单中选择一个选项,然后调用refresh_table
。
将标签文本更改为“正在执行”。
执行print_data
并在树形视图中打印内容。
完成print_data
后,将标签更改为“完成”。
这是东西。当我选择该选项时,程序将存储(按预期方式)来做事。但是,标签一开始并没有更改为“正在执行”。相反,当print_data
执行完毕(几乎同时执行)时,它将更改为“完成”。我怀疑一旦完成所有需求,命令refresh_table
就会影响目标小部件。因为我确实看到标签闪烁为“正在执行”,但立即显示为“完成”。对这种情况有什么想法吗?任何建议表示赞赏。谢谢!
答案 0 :(得分:2)
我怀疑一旦完成所有需求,命令refresh_table就会影响目标小部件。
是的。每次输入mainloop
时,GUI都会更新。当函数refresh_table
运行时,将不会处理任何事件(例如更新标签),因为这些事件仅在空闲时间发生(因此,它们的其他名称为“空闲任务”)。但是,由于在执行refresh_table
期间UI并不空闲,因此直到函数中的所有代码都完成(因为整个程序在同一线程上运行)并且重绘事件未决之前,事件循环才可访问。您可以通过调用update_idletasks
来解决此问题,它将立即处理所有未决事件。可以这样进行(假设您的主窗口名为parent
,并且您位于类定义中,重要的是在更改标签文本后立即在主窗口中调用update_idletasks
):
def refresh_table(self, args):
label['text'] = 'Executing'
self.parent.update_idletasks()
print_data()
label['text'] = 'Done'
还有update
,它不仅调用待处理的空闲任务,而且基本上处理要处理的所有事情,这在您的情况下是不必要的。 {p} {3}}可以很好地解释为什么update_idletasks
比update
更受欢迎。