分享我使用TQDM和TK的实验,参考了可爱的@xmcp和@runDOSrun的答案
不好的例子
进度条在一个方法中创建并完成 - 结果是程序似乎会挂起,直到完成的进度条弹出。
from tqdm.tk import tqdm
from time import sleep
from tkinter import Tk, Button
window = Tk()
def run_task():
pbar = tqdm(total=30, tk_parent=window)
for _ in range(30):
sleep(0.1)
pbar.update(1)
start_button = Button(window, text="Start", command=run_task)
start_button.pack()
window.mainloop()
基本工作示例
还添加了几行代码,当你按下按钮时禁用它,并在结束时重新启用。如果不加这两行代码,再次按下按钮会重新启动进度条。
from tqdm.tk import tqdm
from time import sleep
from tkinter import Tk, Button
window = Tk()
pbar = tqdm(tk_parent=window)
pbar._tk_window.withdraw()
def run_task():
start_button['state'] = 'disabled'
pbar._tk_window.deiconify()
pbar.reset(total=30)
for _ in range(30):
sleep(0.1)
pbar.update(1)
pbar._tk_window.withdraw()
start_button['state'] = 'normal'
start_button = Button(window, text="Start", command=run_task)
start_button.pack()
window.mainloop()
单个进度条;按钮被禁用
如果您省略禁用按钮的步骤,则再次按下按钮会重置进度条。
线程示例
这个示例不需要等待进度条完成。按钮仍然可用,因此如果您连续点击它,就可以同时启动多个进度条。
from tqdm.tk import tqdm
from time import sleep
from tkinter import Tk, Button
import threading
window = Tk()
def run_task():
def threaded_task():
pbar = tqdm(iterable=range(30), total=30, tk_parent=window)
for _ in pbar:
sleep(0.1)
pbar._tk_window.destroy()
threading.Thread(target=threaded_task).start()
start_button = Button(window, text="Start", command=run_task)
start_button.pack()
window.mainloop()
多个进度条
复杂示例
使用ThreadPoolExecutor同时生成多个进度条。主要的进度条应该保持在前景,并在子进程完成时更新。
import random
from tqdm.tk import tqdm
from time import sleep
from tkinter import Tk, Button
import threading
from concurrent.futures import ThreadPoolExecutor
window = Tk()
def run_task():
def threaded_task(iterable: []):
def inner_task(n: int):
pbar = tqdm(iterable=range(n), total=n, tk_parent=window, desc=threading.current_thread().name, grab=False)
for _ in pbar:
sleep(.1)
pbar._tk_window.destroy()
with ThreadPoolExecutor(max_workers=8) as tpe:
pbar = tqdm(tpe.map(inner_task, iterable), total=len(iterable), grab=True, desc="Main progress bar")
pbar._tk_window.attributes('-topmost', True)
pbar._tk_window.focus_get()
list(pbar)
pbar._tk_window.destroy()
threading.Thread(target=threaded_task, kwargs={'iterable': random.sample(range(1, 100), 20)}).start()
start_button = Button(window, text="Start", command=run_task)
start_button.pack()
window.mainloop()
多个进度条同时运行
为了可用性,你几乎肯定想使用线程示例 - 基本的工作示例会重复使用一个预定义的进度条,而且有点笨拙。使用线程示例,你不必事先知道需要多少进度条。
你也可以完全禁用线程示例中的按钮,以防止多个并发激活。
ttk
包含一个ttk.Progressbar
类。 - Luke Taylor