在 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()