如何在Tkinter主脚本中实时获取Converter.py的progress_percent变量
问题描述
尝试在Tkinter的main.py中实时获取Converter.py脚本里的progress_percent变量以更新进度条,但无法实现,代码示例如下:
main.py
# Tkinter Imports from tkinter import * from tkinter import ttk from tkinter import filedialog # other imports import os from Converter import * from threading import Thread # functions # file explorer window def browseFiles(): global filename filename = filedialog.askopenfilename( initialdir="/", title="Select a File", filetypes=(("all files", "*.*"), ("Text files", "*.txt*")) ) filename = filename.replace(" ", "_") # Change label contents label_file_explorer.configure(text="File Opened: " + filename.replace(" ", "_")) global fileNoExt fileNoExt = os.path.splitext(filename)[0] def ConvertCommand(): convertingThread = Thread(target=convert, args=(filename, fileNoExt, OutputType)) convertingThread.start() # Options root = Tk() root.title("AsterConv") root.geometry("900x900") root["bg"] = "#011627" # creating Elements label_file_explorer = Label( root, text="File Explorer using Tkinter", width=40, height=4, fg="blue" ) button_explore = Button(root, text="Browse Files", command=browseFiles) button_exit = Button(root, text="Exit", command=exit) OutputType = StringVar(root) OutputType.set("mp4") # default value ConvertType = OptionMenu(root, OutputType, "mp4", "mkv", "mkv", "webm") ConvertBtn = Button(root, text="Convert", command=ConvertCommand) ProgressBar = ttk.Progressbar(root, orient="horizontal", mode="determinate", length=280) ProgressBar["value"] = 0 # placing elements label_file_explorer.grid(column=0, row=0) button_explore.grid(column=0, row=1) button_exit.grid(column=0, row=2) ConvertType.grid(column=1, row=0) ConvertBtn.grid(column=1, row=1) ProgressBar.grid(column=0, row=3, columnspan=2, padx=10, pady=20) root.mainloop()
Converter.py
import subprocess as sp import shlex import json from threading import Thread import time # 模块级别声明全局变量,供main.py引用 progress_percent = 0 def convert(filename, fileNoExt, OutputType): global progress_percent OutputFile = fileNoExt + "." + OutputType.get() def progress_reader(procs, q): while True: if procs.poll() is not None: break progress_text = procs.stdout.readline() if not progress_text: break progress_text = progress_text.decode("utf-8") if progress_text.startswith("frame="): frame = int(progress_text.partition("=")[-1]) q[0] = frame data = sp.run( shlex.split( "ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of json " + filename ), stdout=sp.PIPE, ).stdout dict_data = json.loads(data) tot_n_frames = float(dict_data["streams"][0]["nb_read_packets"]) process = sp.Popen( shlex.split( "ffmpeg -y -loglevel error -i " + filename + " -progress pipe:1 " + OutputFile ), stdout=sp.PIPE, ) q = [0] progress_reader_thread = Thread(target=progress_reader, args=(process, q)) progress_reader_thread.start() while True: if process.poll() is not None: break time.sleep(0.5) n_frame = q[0] progress_percent = (n_frame / tot_n_frames) * 100 print(f"Progress [%]: {progress_percent:.2f}") progress_percent = 0 process.stdout.close() progress_reader_thread.join() process.wait()
解决方案
问题核心:跨模块全局变量声明位置错误,且Tkinter不会自动监听变量变化刷新GUI;子线程不能直接操作Tkinter组件,必须通过主线程更新。
修复步骤
- 修正全局变量声明:在
Converter.py模块顶部声明progress_percent,确保main.py能正确引用 - 添加进度条自动更新逻辑:在
main.py中用Tkinter的after()方法定时读取进度值并更新进度条,所有GUI操作必须在主线程执行 - 修复代码细节:修正
browseFiles的语法错误、ConvertBtn的文本错误、避免覆盖内置类型dict等
修改后的main.py关键新增代码
在ConvertCommand函数后添加:
def update_progress(): # 读取Converter模块的进度值并更新进度条 ProgressBar["value"] = progress_percent # 每隔500毫秒重复调用,持续更新 root.after(500, update_progress)
在root.mainloop()前启动更新循环:
update_progress() root.mainloop()
修改后,主线程会定时同步Converter.py的进度值,既规避了子线程操作GUI的风险,也解决了跨模块变量的引用问题。
内容的提问来源于stack exchange,提问作者Aster Over Heaven
相关产品推荐
相关产品推荐

