1
1

【Python】Tkinterで2つのデータを結合し出力するGUIアプリを作成する

Posted at

はじめに

本記事ではPythonのTkinterライブラリを使って2つのデータ(今回はcsvとエクセル)を結合し出力するGUIアプリを作成します。

作成したGUIアプリについて

今回作成したGUIアプリは以下の通りです。

実装機能

  1. 結合に使うデータをダイアログで選択する
  2. 出力データを格納するフォルダをダイアログで選択する
  3. 結合・出力処理を実行する
  4. 結合ファイル・出力フォルダが未選択の場合、アラートを出す
  5. 処理実行中は処理中のプログレスバーを出す
  6. 処理が終わったら完了のメッセージを出す

画面

  • 初期画面
    image.png
     
  • ダイアログの表示(参照ボタン押下時)
    image.png
     
  • 結合ファイル・出力フォルダが未選択時
    image.png
     
  • 処理中(プログレスバーを表示する)
    image.png
     
  • 処理完了時
    image.png

使用データについて

今回は以下2つのデータのIDをキーに結合し出力します。

  • データ1(csv)
ID 名前
1A 田中
1B 小林
1C 佐藤
1D 伊藤
  • データ2(Excel)
ID 住所
1A 東京
1B 埼玉
1D 神奈川
  • 出力
ID 名前 住所
1A 田中 東京
1B 小林 埼玉
1C 佐藤
1D 伊藤 神奈川

実装環境

python 3.10.4
Windows 11 Home

作成コード

作成したコードは以下になります。

import os
import pandas as pd
import threading
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog

class Application(tk.Frame):
    def __init__(self,master):
        super().__init__(master)
        self.pack()
        #タイトルの設定
        self.master.title("csv・Excel結合")

        self.set_csv_widgets()
        self.set_excel_widgets()
        self.set_output_widgets()
        self.set_run_widgets()

    # csv関連(ラベル、テキストボックス、参照ボタン)のパーツを配置する
    def set_csv_widgets(self):
        self.csv_frame = ttk.Frame(self, padding=10)
        self.csv_frame.grid(row=0, column=1, sticky=E)

        self.csv_label = ttk.Label(self.csv_frame, text="csvファイル:", padding=(5, 2))
        self.csv_label.pack(side=LEFT)

        self.csv_entry = StringVar()
        self.csv_dir = ttk.Entry(self.csv_frame, textvariable=self.csv_entry, width=70)
        self.csv_dir.pack(side=LEFT)

        self.csv_button = ttk.Button(self.csv_frame, text="参照", command=self.file_dialog_csv_clicked)
        self.csv_button.pack(side=LEFT)

    # Excel関連(ラベル、テキストボックス、参照ボタン)のパーツを配置する
    def set_excel_widgets(self):
        self.excel_frame = ttk.Frame(self, padding=10)
        self.excel_frame.grid(row=2, column=1, sticky=E)

        self.excel_label = ttk.Label(self.excel_frame, text="Excelファイル:", padding=(5, 2))
        self.excel_label.pack(side=LEFT)

        self.excel_entry = StringVar()
        self.excel_dir = ttk.Entry(self.excel_frame, textvariable=self.excel_entry, width=70)
        self.excel_dir.pack(side=LEFT)

        self.excel_button = ttk.Button(self.excel_frame, text="参照", command=self.file_dialog_excel_clicked)
        self.excel_button.pack(side=LEFT)

    # 出力関連(ラベル、テキストボックス、参照ボタン)のパーツを配置する
    def set_output_widgets(self):
        self.output_frame = ttk.Frame(self, padding=10)
        self.output_frame.grid(row=4, column=1, sticky=E)

        self.output_label = ttk.Label(self.output_frame, text="出力フォルダ:", padding=(5, 2))
        self.output_label.pack(side=LEFT)

        self.output_entry = StringVar()
        self.output_dir = ttk.Entry(self.output_frame, textvariable=self.output_entry, width=70)
        self.output_dir.pack(side=LEFT)

        self.output_button = ttk.Button(self.output_frame, text="参照", command=self.dir_dialog_clicked)
        self.output_button.pack(side=LEFT)

    # 実行関連(ラベル、参照ボタン)のパーツを配置する
    def set_run_widgets(self):
        self.run_frame = ttk.Frame(self, padding=10)
        self.run_frame.grid(row=6,column=1,sticky=E)

        self.run_button = ttk.Button(self.run_frame, text="実行", command=self.run_thread)
        self.run_button.pack(side = RIGHT)

    # 参照ボタン(csv)押下時
    def file_dialog_csv_clicked(self):
        #csvファイル指定のダイアログを出す
        fTyp = [("", "csv")]
        iFile = os.path.abspath(os.path.dirname(__file__))
        iFilePath = filedialog.askopenfilename(filetype = fTyp, initialdir = iFile)
        self.csv_entry.set(iFilePath)

    # 参照ボタン(Excel)押下時
    def file_dialog_excel_clicked(self):
        #Excelファイル指定のダイアログを出す
        fTyp = [("", "xlsx")]
        iFile = os.path.abspath(os.path.dirname(__file__))
        iFilePath = filedialog.askopenfilename(filetype = fTyp, initialdir = iFile)
        self.excel_entry.set(iFilePath)

    # 参照ボタン(出力)押下時
    def dir_dialog_clicked(self):
        #出力フォルダ指定のダイアログを出す
        iDir = os.path.abspath(os.path.dirname(__file__))
        iDirPath = filedialog.askdirectory(initialdir = iDir)
        self.output_entry.set(iDirPath)

    #実行ボタン押下時の処理をスレッドで行う(プログレスバーを動かすため)
    def run_thread(self):
        threading.Thread(target=self.run_clicked, daemon=True).start()

    # 実行ボタン押下時
    def run_clicked(self):
        self.set_progress_widgets()

        alert_text = self.check_file_path()
        if alert_text == "":
            #ファイル、フォルダのパスが指定されている場合、処理を実行する
            self.merge_file()
            self.delete_progress()
            messagebox.showinfo("info", "処理が完了しました")
        else:
            #ファイル、フォルダのパスが指定されていない場合、アラートを出して処理を終了する
            self.delete_progress()
            messagebox.showinfo("info", alert_text)

    #処理中のラベルとプログレスバーを設置する
    def set_progress_widgets(self):
        self.process = ttk.Label(self.run_frame, text="処理中・・・")
        self.process.pack(side=LEFT)
        self.process.update()

        var = tk.IntVar()
        self.pb=ttk.Progressbar(self.run_frame,maximum=100,mode="indeterminate",variable=var)
        self.pb.pack(side=LEFT)
        self.pb.start(interval=10)

    #パスが設定されているか確認する
    def check_file_path(self):
        alert_text = ""

        csv_path = self.csv_entry.get()
        excel_path = self.excel_entry.get()
        output_path = self.output_entry.get()
        if csv_path == '':
            alert_text += "csvファイル" + "\n"
        if excel_path == '':
            alert_text += "excelファイル" + "\n"
        if output_path == '':
            alert_text += "出力フォルダ" 

        if alert_text:
            alert_text = "以下のファイルの指定がありません" + "\n" + alert_text
        
        return alert_text

    #csvとexcelを結合する
    def merge_file(self):
        csv_path = self.csv_entry.get()
        excel_path = self.excel_entry.get()

        csv_df = pd.read_csv(csv_path)        
        excel_df = pd.read_excel(excel_path)

        join_df = pd.merge(csv_df, excel_df, on=["ID"], how="left")

        output_dir = self.output_entry.get() + "\出力.xlsx"
        join_df.to_excel(output_dir,index=FALSE)

    #処理中のラベルとプログレスバーの削除する
    def delete_progress(self):
        self.process.destroy()
        self.pb.destroy()

def main():
    root = tk.Tk()
    app = Application(master=root)
    app.mainloop()

if __name__ == "__main__":
    main()

終わりに

今回はPythonのTkinterライブラリを使って2つのデータ(今回はcsvとエクセル)を結合し出力するGUIアプリを作成しました。
ファイルの選択やプログレスバーの表示はTkinterを用いた他のGUIアプリを作成する際にも利用が出来そうだと感じました。
ご参考になれば幸いです。

参考

この記事は以下の記事を参考にして執筆しました。
【Python】tkinterでファイル&フォルダパス指定画面を作成する
【Python】Tkinterのテンプレート
【Python】Tkinterを使った雛形(クラス化手法)
Threading with Tkinter to introduce Progress bar

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1