如何使用 tkinter 增量打印到 GUI
How to incrementally print to GUI using tkinter
我想使用 tkinter 在 GUI 中逐步打印出 main
函数的进度。因为我计划使用 PyInstaller 将我的 python 代码打包到 .exe
文件中,我的用户不喜欢在控制台中阅读日志。
我在这里写了我的代码,但目前有两个问题。
- 最新的文字覆盖在之前的文字之上。所以我看不到过去的文字。
- 仅当整个函数完成后才打印文本运行。所以现在有大约一分钟的计算时间,当它完成时,它只显示最后一个文本
Job 3 done
.
import tkinter as tk
master = tk.Tk()
master.geometry('600x600')
tk.Label(master, text="days").grid(row=0)
tk.Label(master, text="coefficients").grid(row=1)
tk.Label(master, text="log").grid(row=5)
e1 = tk.Entry(master)
e2 = tk.Entry(master)
e1.insert(10, 0)
e2.insert(10, 0.5)
e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
lower_frame = tk.Frame(master, bg='#80c1ff', bd='5')
lower_frame.place(relx=0.5, rely=0.25, relwidth=0.75, relheight=0.6, anchor='n')
lower_label = tk.Label(lower_frame)
lower_label.place(relwidth=1, relheight=1)
def main():
# do job 1
lower_label.config(text="Job 1 done")
# do job 2
lower_label.config(text="Job 2 done")
# do job 3
lower_label.config(text="Job 3 done")
b = tk.Button(master, text="run", command=main).grid(row=3,
column=1,
sticky=tk.W,
pady=4)
master.mainloop()
tk.mainloop()
我的代码目前在 GUI 上输出
_______________
| Job 3 done |
|_______________|
我的预期行为
_______________
| Job 1 done |
| Job 2 done |
| Job 3 done |
|_______________|
我该如何解决这个问题?问题 2 不如问题 1 重要,所以我想至少找到问题 1 的解决方案。谢谢您的帮助。
将 main()
函数的主体更改为:
lower_label.config(text="Starting jobs...")
master.update()
import time
time.sleep(2) # do job 1
lower_label.config(text="Job 1 done.")
master.update()
time.sleep(2) # do job 2
lower_label.config(text=lower_label['text'] + "\nJob 2 done.")
master.update()
time.sleep(2) # do job 3
lower_label.config(text=lower_label['text'] + "\nJob 3 done.")
master.update()
只显示“Job 3 done”的原因是您每次都用新内容覆盖标签文本,直到使用最终文本(未被覆盖)。所以我让它重复使用以前的文本,同时向其附加您想要的新文本。
要点:您会注意到我在更新标签后立即写了master.update()
。如果我不这样做,在 main()
函数完成之前您将看不到任何文本更改。
因为tkinter mainloop还没有收回控制权所以标签上的变化没有更新。您需要在每次更改后调用 lower_label.update()
以强制更新。
对于你的情况,最好使用 Text
而不是 Label
:
lower_frame = tk.Frame(master, bg='#80c1ff', bd='5')
lower_frame.place(relx=0.5, rely=0.25, relwidth=0.75, relheight=0.6, anchor='n')
log_box = tk.Text(lower_frame, state='disabled')
log_box.place(relwidth=1, relheight=1)
def log(msg):
log_box.config(state='normal')
log_box.insert('end', msg+'\n')
log_box.see('end')
log_box.config(state='disabled')
log_box.update()
def main():
# do job 1
log("Job 1 done")
# do job 2
log("Job 2 done")
# do job 3
log("Job 3 done")
我想使用 tkinter 在 GUI 中逐步打印出 main
函数的进度。因为我计划使用 PyInstaller 将我的 python 代码打包到 .exe
文件中,我的用户不喜欢在控制台中阅读日志。
我在这里写了我的代码,但目前有两个问题。
- 最新的文字覆盖在之前的文字之上。所以我看不到过去的文字。
- 仅当整个函数完成后才打印文本运行。所以现在有大约一分钟的计算时间,当它完成时,它只显示最后一个文本
Job 3 done
.
import tkinter as tk
master = tk.Tk()
master.geometry('600x600')
tk.Label(master, text="days").grid(row=0)
tk.Label(master, text="coefficients").grid(row=1)
tk.Label(master, text="log").grid(row=5)
e1 = tk.Entry(master)
e2 = tk.Entry(master)
e1.insert(10, 0)
e2.insert(10, 0.5)
e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
lower_frame = tk.Frame(master, bg='#80c1ff', bd='5')
lower_frame.place(relx=0.5, rely=0.25, relwidth=0.75, relheight=0.6, anchor='n')
lower_label = tk.Label(lower_frame)
lower_label.place(relwidth=1, relheight=1)
def main():
# do job 1
lower_label.config(text="Job 1 done")
# do job 2
lower_label.config(text="Job 2 done")
# do job 3
lower_label.config(text="Job 3 done")
b = tk.Button(master, text="run", command=main).grid(row=3,
column=1,
sticky=tk.W,
pady=4)
master.mainloop()
tk.mainloop()
我的代码目前在 GUI 上输出
_______________
| Job 3 done |
|_______________|
我的预期行为
_______________
| Job 1 done |
| Job 2 done |
| Job 3 done |
|_______________|
我该如何解决这个问题?问题 2 不如问题 1 重要,所以我想至少找到问题 1 的解决方案。谢谢您的帮助。
将 main()
函数的主体更改为:
lower_label.config(text="Starting jobs...")
master.update()
import time
time.sleep(2) # do job 1
lower_label.config(text="Job 1 done.")
master.update()
time.sleep(2) # do job 2
lower_label.config(text=lower_label['text'] + "\nJob 2 done.")
master.update()
time.sleep(2) # do job 3
lower_label.config(text=lower_label['text'] + "\nJob 3 done.")
master.update()
只显示“Job 3 done”的原因是您每次都用新内容覆盖标签文本,直到使用最终文本(未被覆盖)。所以我让它重复使用以前的文本,同时向其附加您想要的新文本。
要点:您会注意到我在更新标签后立即写了master.update()
。如果我不这样做,在 main()
函数完成之前您将看不到任何文本更改。
因为tkinter mainloop还没有收回控制权所以标签上的变化没有更新。您需要在每次更改后调用 lower_label.update()
以强制更新。
对于你的情况,最好使用 Text
而不是 Label
:
lower_frame = tk.Frame(master, bg='#80c1ff', bd='5')
lower_frame.place(relx=0.5, rely=0.25, relwidth=0.75, relheight=0.6, anchor='n')
log_box = tk.Text(lower_frame, state='disabled')
log_box.place(relwidth=1, relheight=1)
def log(msg):
log_box.config(state='normal')
log_box.insert('end', msg+'\n')
log_box.see('end')
log_box.config(state='disabled')
log_box.update()
def main():
# do job 1
log("Job 1 done")
# do job 2
log("Job 2 done")
# do job 3
log("Job 3 done")