Output interim results in new window during tkinter mainloop - Threading
Building on @HenryYik answer, which shows the correct approach but throws a RuntimeError
when attempting to click calculate
several times in a row:
RuntimeError: threads can only be started once
The following example pops a tk.Toplevel
that shows the intermediate results, and allows clicking repeatedly the calculate
button. It will spawn as many toplevel windows, showing as many intermediate results.
Each new thread is identified by a unique number; a console output is printed when a thread is done.
The close
button on the Toplevel
becomes active when the calculation finishes.
import tkinter as tkimport threadingimport timedef 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 = Nonebutton_calc = tk.Button(root,text="Calculate",command=get_and_start_thread)button_calc.pack(side=tk.TOP)root.mainloop()
You need to thread the function that does the calculation, which is func
. Right now you are threading the creation of another Tk instance and some widgets.
It can be something like this:
import tkinter as tkimport threadingimport time as tdef 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()