Zenn
🔖

Pythonでプログレスバーを表示する

2025/03/02に公開

PythonとTkinterを使用してプログレスバーを表示し処理の進捗状況を表示するコードをまとめていきます
こちらのコードはChatGPTを使用して作成しています

プログレスバーを表示するコード

from tkinter import Tk, Toplevel, ttk

class ProgressBarApp:
    def __init__(self, maximum):
        self.root = Tk()
        self.root.withdraw()

        # プログレスバーのウィンドウを作成
        self.progress_window = Toplevel(self.root)
        self.progress_window.title("処理中")
        self.progress_bar = ttk.Progressbar(self.progress_window, orient="horizontal", length=300, mode="determinate") # ①
        self.progress_bar.pack(pady=20)
        self.progress_bar["maximum"] = maximum # ②

        # 画面の中央に表示: ③
        self.progress_window.update_idletasks()
        width = self.progress_window.winfo_width()
        height = self.progress_window.winfo_height()
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width // 2) - (width // 2)
        y = (screen_height // 2) - (height // 2)
        self.progress_window.geometry(f'{width}x{height}+{x}+{y}')
        self.progress_window.deiconify()

    # プログレスバーの進捗状況の表示を更新: ④
    def update_progress(self, value):
        self.progress_bar["value"] = value
        self.progress_window.update()

    # プログレスバーアプリを終了
    def close(self):
        self.progress_window.destroy()
        self.root.quit()

コードの解説

ttk.Progressbarが時間のかかる作業などの進捗状況をユーザーに示すためのウィジェットを
表示するコードになります
オプションの詳しい説明は下記のサイトを参照してください
https://python.keicode.com/advanced/tkinter-widget-progressbar.php

ここでは、プログレスバーの進捗状況がいくつになったら100%になるのかを指定します
ここで設定する数字は100である必要はなく、処理するファイルの数やデータの行数などが入ります
update_progressメソッドの引数がここで設定した数と一致すると進捗状況が100%で表示されます

コメントにも記載されていますが、画面中央にプログレスバーを表示するためのコードです
これを入れない場合は左上端にプログレスバーが表示されますが、
見づらく不格好なのでこのコードを作成しています

画面の縦と横のサイズとプログレスバーの縦と横のサイズから中央に表示できる座標を割り出して、
その座標に合わせてプログレスバーを表示します

進捗状況をprogress_bar["value"]に設定して、次の行のupdateで画面に反映しています
progress_bar["value"]に設定する値は整数である必要はなく、「3.5」などの値も設定できます

使用例

A列に数字が入っているcsvファイルから数字を集計してメッセージに表示するコード
下記のコードでは「chardet」と「pandas」のパッケージをインストールする必要があります

import chardet
import pandas as pd
import io
from tkinter import Tk, Toplevel, ttk, filedialog, messagebox

class ProgressBarApp:
    def __init__(self, maximum):
        self.root = Tk()
        self.root.withdraw()

        # プログレスバーのウィンドウを作成
        self.progress_window = Toplevel(self.root)
        self.progress_window.title("処理中")
        self.progress_bar = ttk.Progressbar(self.progress_window, orient="horizontal", length=300, mode="determinate")
        self.progress_bar.pack(pady=20)
        self.progress_bar["maximum"] = maximum

        # 画面の中央に表示
        self.progress_window.update_idletasks()
        width = self.progress_window.winfo_width()
        height = self.progress_window.winfo_height()
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width // 2) - (width // 2)
        y = (screen_height // 2) - (height // 2)
        self.progress_window.geometry(f'{width}x{height}+{x}+{y}')
        self.progress_window.deiconify()

    # プログレスバーの進捗状況の表示を更新
    def update_progress(self, value):
        self.progress_bar["value"] = value
        self.progress_window.update()

    # プログレスバーアプリを終了
    def close(self):
        self.progress_window.destroy()
        self.root.quit()

def process_csv_file(csv_files):
    progress_app = ProgressBarApp(len(csv_files))

    for file_index, csv_file in enumerate(csv_files):
        # ファイルのエンコーディングを検出
        with open(csv_file, 'rb') as f:
            result = chardet.detect(f.read())
            encoding = result['encoding']

        # CSVファイルの読み込み
        with open(csv_file, 'r', encoding=encoding, errors='replace') as f:
            content = f.read()
            data = pd.read_csv(io.StringIO(content))

        total_sum = 0
        for index, row in data.iterrows():
            total_sum += int(row.iloc[0])
            progress = index / len(data)
            progress_app.update_progress(file_index + progress)

    messagebox.showinfo("合計", f"合計数: {total_sum}")
    progress_app.close()

# CSVファイルを選択
csv_files = filedialog.askopenfilenames(title='csvファイルを選択してください', filetypes=[("CSV", "*.csv")])
if csv_files:
    process_csv_file(csv_files)
else:
    messagebox.showerror("エラー", "CSVファイルが選択されていません")

Discussion

ログインするとコメントできます