You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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组件,必须通过主线程更新。

修复步骤

  1. 修正全局变量声明:在Converter.py模块顶部声明progress_percent,确保main.py能正确引用
  2. 添加进度条自动更新逻辑:在main.py中用Tkinter的after()方法定时读取进度值并更新进度条,所有GUI操作必须在主线程执行
  3. 修复代码细节:修正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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 11:58:10