如何使用 tkinter 增量打印到 GUI

How to incrementally print to GUI using tkinter

我想使用 tkinter 在 GUI 中逐步打印出 main 函数的进度。因为我计划使用 PyInstaller 将我的 python 代码打包到 .exe 文件中,我的用户不喜欢在控制台中阅读日志。

我在这里写了我的代码,但目前有两个问题。

  1. 最新的文字覆盖在之前的文字之上。所以我看不到过去的文字。
  2. 仅当整个函数完成后才打印文本运行。所以现在有大约一分钟的计算时间,当它完成时,它只显示最后一个文本 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")