在tkinter主循环期间,输出临时结果会在新窗口中显示-线程处理

时间:2019-04-28 20:40:23

标签: python python-3.x tkinter python-multithreading

我正在为数学应用程序设计GUI。由于计算通常需要一些时间,因此我想将临时结果输出到新的tkinter窗口中的文本字段,该窗口将在启动计算时打开。

我已经打开了一个新窗口并进行了计算,但是结果将在计算结束后打印出来。

我准备了一个简短的代码片段,展示了我的方法:

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。 但是,并非总是会出现此错误。

欢呼

2 个答案:

答案 0 :(得分:2)

以@HenryYik答案为基础,该答案显示了正确的方法,但是在尝试连续单击RuntimeError多次时抛出calculate

RuntimeError: threads can only be started once

以下示例弹出一个显示中间结果的tk.Toplevel,并允许重复单击calculate按钮。它会产生尽可能多的顶级窗口,并显示尽可能多的中间结果。
每个新线程均由唯一编号标识;线程完成后,将输出控制台输出。

计算完成后,close上的Toplevel按钮将变为活动状态。

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

答案 1 :(得分:1)

您需要线程执行计算的函数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()