はじめに
本記事ではPythonのTkinterライブラリを使って2つのデータ(今回はcsvとエクセル)を結合し出力するGUIアプリを作成します。
作成したGUIアプリについて
今回作成したGUIアプリは以下の通りです。
実装機能
- 結合に使うデータをダイアログで選択する
- 出力データを格納するフォルダをダイアログで選択する
- 結合・出力処理を実行する
- 結合ファイル・出力フォルダが未選択の場合、アラートを出す
- 処理実行中は処理中のプログレスバーを出す
- 処理が終わったら完了のメッセージを出す
画面
使用データについて
今回は以下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