在 tkinter mainloop 期间输出新的 window 中的临时结果 - 线程
Output interim results in new window during tkinter mainloop - Threading
我正在为数学应用程序开发 GUI。由于计算通常需要一些时间,我想将中间结果输出到新的 tkinter window 中的文本字段,该 tkinter window 将在启动计算时打开。
我已经到了能够打开一个新的 window 并进行计算的地步,但是结果在计算结束后打印出来。
我准备了一个简短的代码片段来展示我的方法:
import tkinter as tk
import threading
import time as t
class CalculationDialog(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.start()
self.root = tk.Tk()
self.textField = tk.Text(self.root)
self.bCloseDialog = tk.Button(self.root, text="Close", state=tk.DISABLED, command=self.root.destroy)
self.textField.grid(row=1, column=0)
self.bCloseDialog.grid(row=2, column=0)
def callback(self):
self.root.quit()
def run(self):
self.root.protocol("WM_DELETE_WINDOW", self.callback)
self.root.mainloop()
def calculate():
app = CalculationDialog()
# Conduct calculation and output to textfield of app
func(app.textField,0)
def func(output,input):
for i in range(input,100):
result = i**2
output.insert(tk.END,str(result)+"\n")
t.sleep(0.1)
main = tk.Tk()
buttonCalc = tk.Button(main,text="Calculate",command=calculate)
buttonCalc.pack(side=tk.TOP)
main.mainloop()
有人对我缺少的东西有什么建议吗?
我有时会收到一条错误消息,指出 CalculationDialog
没有属性 root
。
但是,并不总是会出现此错误。
干杯
您需要线程化执行计算的函数,即 func
。现在您正在线程化另一个 Tk 实例和一些小部件的创建。
可以是这样的:
import tkinter as tk
import threading
import time as t
def func():
frame = tk.Frame(root)
frame.pack()
textField = tk.Text(frame)
bCloseDialog = tk.Button(frame, text="Close", state=tk.DISABLED, command=root.destroy)
textField.grid(row=1, column=0)
bCloseDialog.grid(row=2, column=0)
for i in range(1,100):
result = i**2
textField.insert(tk.END,str(result)+"\n")
t.sleep(0.1)
root = tk.Tk()
thr = threading.Thread(target=func)
buttonCalc = tk.Button(root,text="Calculate",command=thr.start)
buttonCalc.pack(side=tk.TOP)
root.mainloop()
基于@HenryYik 的回答,它显示了正确的方法,但在尝试连续多次单击 calculate
时抛出 RuntimeError
:
RuntimeError: threads can only be started once
以下示例弹出一个显示中间结果的 tk.Toplevel
,并允许重复单击 calculate
按钮。它将生成尽可能多的顶层 windows,显示尽可能多的中间结果。
每个新线程都由一个唯一的编号标识;线程完成后打印控制台输出。
Toplevel
上的 close
按钮在计算完成后激活。
import tkinter as tk
import threading
import time
def func(thread_number=[0]): # note: the mutable default arg creates a closure that keeps track of the thread number.
global thr
local_thread_number = thread_number[0]
thread_number[0] += 1
def close():
thr = None
top.destroy()
top = tk.Toplevel(root)
text_field = tk.Text(top)
close_btn = tk.Button(top, text="Close", state=tk.DISABLED, command=close)
text_field.grid(row=1, column=0)
close_btn.grid(row=2, column=0)
for i in range(1, 100):
result = i**2
if i % 10 == 0:
text_field.insert(tk.END, str(result)+"\n")
time.sleep(0.05)
print(f'thread {local_thread_number} done!')
close_btn.config(state=tk.NORMAL)
def get_and_start_thread():
global thr
thr = threading.Thread(target=func)
thr.start()
root = tk.Tk()
thr = None
button_calc = tk.Button(root,text="Calculate",command=get_and_start_thread)
button_calc.pack(side=tk.TOP)
root.mainloop()
我正在为数学应用程序开发 GUI。由于计算通常需要一些时间,我想将中间结果输出到新的 tkinter window 中的文本字段,该 tkinter window 将在启动计算时打开。
我已经到了能够打开一个新的 window 并进行计算的地步,但是结果在计算结束后打印出来。
我准备了一个简短的代码片段来展示我的方法:
import tkinter as tk
import threading
import time as t
class CalculationDialog(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.start()
self.root = tk.Tk()
self.textField = tk.Text(self.root)
self.bCloseDialog = tk.Button(self.root, text="Close", state=tk.DISABLED, command=self.root.destroy)
self.textField.grid(row=1, column=0)
self.bCloseDialog.grid(row=2, column=0)
def callback(self):
self.root.quit()
def run(self):
self.root.protocol("WM_DELETE_WINDOW", self.callback)
self.root.mainloop()
def calculate():
app = CalculationDialog()
# Conduct calculation and output to textfield of app
func(app.textField,0)
def func(output,input):
for i in range(input,100):
result = i**2
output.insert(tk.END,str(result)+"\n")
t.sleep(0.1)
main = tk.Tk()
buttonCalc = tk.Button(main,text="Calculate",command=calculate)
buttonCalc.pack(side=tk.TOP)
main.mainloop()
有人对我缺少的东西有什么建议吗?
我有时会收到一条错误消息,指出 CalculationDialog
没有属性 root
。
但是,并不总是会出现此错误。
干杯
您需要线程化执行计算的函数,即 func
。现在您正在线程化另一个 Tk 实例和一些小部件的创建。
可以是这样的:
import tkinter as tk
import threading
import time as t
def func():
frame = tk.Frame(root)
frame.pack()
textField = tk.Text(frame)
bCloseDialog = tk.Button(frame, text="Close", state=tk.DISABLED, command=root.destroy)
textField.grid(row=1, column=0)
bCloseDialog.grid(row=2, column=0)
for i in range(1,100):
result = i**2
textField.insert(tk.END,str(result)+"\n")
t.sleep(0.1)
root = tk.Tk()
thr = threading.Thread(target=func)
buttonCalc = tk.Button(root,text="Calculate",command=thr.start)
buttonCalc.pack(side=tk.TOP)
root.mainloop()
基于@HenryYik 的回答,它显示了正确的方法,但在尝试连续多次单击 calculate
时抛出 RuntimeError
:
RuntimeError: threads can only be started once
以下示例弹出一个显示中间结果的 tk.Toplevel
,并允许重复单击 calculate
按钮。它将生成尽可能多的顶层 windows,显示尽可能多的中间结果。
每个新线程都由一个唯一的编号标识;线程完成后打印控制台输出。
Toplevel
上的 close
按钮在计算完成后激活。
import tkinter as tk
import threading
import time
def func(thread_number=[0]): # note: the mutable default arg creates a closure that keeps track of the thread number.
global thr
local_thread_number = thread_number[0]
thread_number[0] += 1
def close():
thr = None
top.destroy()
top = tk.Toplevel(root)
text_field = tk.Text(top)
close_btn = tk.Button(top, text="Close", state=tk.DISABLED, command=close)
text_field.grid(row=1, column=0)
close_btn.grid(row=2, column=0)
for i in range(1, 100):
result = i**2
if i % 10 == 0:
text_field.insert(tk.END, str(result)+"\n")
time.sleep(0.05)
print(f'thread {local_thread_number} done!')
close_btn.config(state=tk.NORMAL)
def get_and_start_thread():
global thr
thr = threading.Thread(target=func)
thr.start()
root = tk.Tk()
thr = None
button_calc = tk.Button(root,text="Calculate",command=get_and_start_thread)
button_calc.pack(side=tk.TOP)
root.mainloop()