我需要写一个简单的UI,并且做一个进度条,目前用的是 ttk.Progressbar(),并且用variable对接一个变量来更新进度条的值。
import time
from threading import Thread
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.filedialog as fd
from tkinter import messagebox, StringVar, IntVar
class UI(tk.Tk):
def __init__(self):
super().__init__()
self.button_size_x = 12
self.button_size_x_2 = 2 # For the 'X' button
self.label_size_x = 12
self.entry_unit_size_x = 40
self.str_win_name = f"UI Test"
self.str_win_size = '390x140'
self.title(self.str_win_name)
self.geometry(self.str_win_size)
self.resizable(False, False)
self.var_entry_0001 = StringVar(self) # folder path
self.var_progress = IntVar(self) # progress value
self.progress = None
self.build_ui()
def clear_entry_0001(self):
self.var_entry_0001.set('')
def select_folder(self):
folder_path = fd.askdirectory()
self.var_entry_0001.set(folder_path)
def show_message(self, msg_no: int, custom_msg: str = None):
if msg_no == 0:
messagebox.showinfo(self.str_win_name, message='Task completed')
def show_error(self, error_no: int, custom_msg: str = None):
if error_no == 0:
messagebox.showerror(self.str_win_name, message='Invalid file root')
def validate_folder_path(self):
folder_path = self.var_entry_0001.get()
if not folder_path.strip():
self.show_error(0)
return folder_path.strip()
def stop_progress(self):
self.progress.stop()
def monitor_progress(self, thread: Thread):
if thread.is_alive():
self.after(100, lambda: self.monitor_progress(thread))
else:
self.stop_progress()
self.show_message(0)
def main_func(self):
for i in range(1, 11):
time.sleep(1)
self.var_progress.set(i*10)
def run_main(self):
# folder_path = self.validate_folder_path()
# if folder_path:
# 单开一个线程运行主函数
thread = Thread(target=self.main_func, daemon=False)
thread.start()
# 监测线程
self.monitor_progress(thread)
def build_ui(self):
frame_001 = ttk.Frame(self)
ttk.Label(frame_001, width=self.label_size_x, text='File Root').grid(row=0, column=0, sticky='W')
ttk.Entry(frame_001, width=self.entry_unit_size_x, textvariable=self.var_entry_0001).grid(row=0, column=1, columnspan=8, sticky='W')
ttk.Button(frame_001, text='X', width=self.button_size_x_2, command=self.clear_entry_0001).grid(row=0, column=9, sticky='W')
ttk.Button(frame_001, text='...', width=self.button_size_x_2, command=self.select_folder).grid(row=0, column=10, sticky='W')
frame_002 = ttk.Frame(self)
ttk.Button(frame_002, text='Run All', width=self.button_size_x, command=self.run_main).grid(row=0, column=0, sticky='W')
self.progress = ttk.Progressbar(frame_002, orient=tk.HORIZONTAL, value=0, maximum=100, length=168, mode='determinate', variable=self.var_progress)
self.progress.grid(row=1, column=0, columnspan=2, sticky='W')
frame_001.pack(side='top', expand=True, fill='both', padx=10, pady=(10, 0))
frame_002.pack(side='top', expand=True, fill='both', padx=10)
if __name__ == '__main__':
DataAnalysis = UI()
DataAnalysis.mainloop()
问题是,实际情况中,并不是简单的每秒更新一次进度条的值,实际情况是,我并不知道主函数会运行多久,这种情况下,要怎么计算进度条的值,有没有常用的方法?
一般是这样做的,首先你把主函数的运行分成多个步骤,比如步骤1—完成10%;步骤2完成20%;步骤3完成30%等等,然后你可以全局声明一个变量或者创建一个进度文件,你每执行完一个步骤后,就把对应的进度放到全局变量或者进度文件中。然后你的进度条功能定时去读取这个全局变量或者进度文件中的值,这样通过中间值的方式做到进度监控。
如果有用的话,麻烦点个采纳哦,谢谢啦