【发布时间】:2021-09-28 19:46:13
【问题描述】:
我正在编写一个 Python GUI 程序,使用 tkinter 根据设置点列表从仪器读取数据,并在程序运行时在 tkinter 滚动文本框中显示每次读取的结果,一旦用户单击“开始” " 按钮。
但是,我的程序仅在所有循环结束时显示结果,而不是在每次循环后更新文本框。在实际使用中,由于测试点较多,程序可能会运行几十分钟。
我尝试使用 .after 方法,让 GUI 更新,但程序不会在每个循环期间更新文本框。
如何修改我的代码,以便在每次循环期间更新 GUI 中的 tkinter 文本框?
这是我使用随机结果作为示例仪器读数的简化代码:
import tkinter as tk
import tkinter.scrolledtext as tkscrolled
from tkinter import ttk
def start_measurement():
import random
test_points = [tp for tp in range(1,5)]
for setpoint in test_points:
data_reading = random.normalvariate(setpoint,0.05/2)
data_results.insert(tk.INSERT,"Setpoint = {:.3f}, Reading = {:.3f}\n".format(setpoint, data_reading))
data_results.after(1000)
data_results.insert(tk.INSERT,"\nDone\n")
root = tk.Tk()
# Create main frame for entire program: mainframe
mainframe = ttk.Frame(root, padding="10 10 10 10", style='bgstyle.TFrame')
mainframe.grid(row=0, column=0, sticky=(tk.N, tk.W, tk.E, tk.S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
# Create Data Output Text Box with Vertical Scrollbar
data_label = ttk.Label(mainframe, text="Results")
data_label.grid(row=1, column=0, padx=(30,30), pady=(20,0), sticky=(tk.S,tk.W,tk.E))
data_results = tkscrolled.ScrolledText(mainframe, width=100, height=20)
data_results.grid(row=2, column=0, padx=(30,30), pady=(0,20), sticky=(tk.N,tk.W,tk.E))
start_button = ttk.Button(mainframe, width=15, text="Start", command=lambda:start_measurement())
start_button.grid(row=0, column=0, padx=(30,30), pady=(20,0), sticky=(tk.N, tk.W))
root.mainloop()
【问题讨论】:
-
简单,不要使用除
.after“循环”以外的任何循环或使用线程(和.after循环) -
Matiiss,我不太明白你的建议“不要使用除 .after "loops" 之外的任何循环”。你能说得更具体点吗?
-
好吧,请不要在
tkinter中使用for、while循环(除非它们非常快或在其他情况下您将它们放入线程和东西中,但不是慢循环在主线程中占用),基本上接受的答案有点像我的意思 -
@Matiiss,知道了。感谢您的澄清。我会尽量坚持使用 .after 递归函数,而不是其他循环。
-
顺便说一句,它们并不完全是递归函数,由于最大递归深度,它们会导致
UnboundLocalError或某事,它们只是在mainloop上放置一个事件,然后从那里调用函数而不是从本身