NINJIN Mail制作記 第2回
前回の課題:Excelの置き場所が固定される問題を解決する
こんにちは、ニンジンです🥕
この記事では、Python標準GUIライブラリ tkinter の filedialog を使って、任意のフォルダにあるExcelファイルを「ファイルを開く」画面から選べるようにする方法を解説します。さらに、config.json に直前に開いたフォルダを記憶させて、次回はその場所を最初に開く機能も実装します。
第1回では、pandasでExcelの中身を読み込むところまで作りました。ただ前回のコードには「プログラムと同じフォルダにExcelを置かないと動かない」という制約がありました。実際の業務では、デスクトップや共有フォルダなど、ファイルの保存場所はさまざまです。この「たかが1クリック」を削るUXの工夫を、現役エンジニア目線でまとめます。
この記事で分かること
tkinter.filedialog.askopenfilename()でExcelファイルを選択するサンプルコードroot.withdraw()で余計な空ウィンドウを隠す理由filetypesで.xlsxだけに絞って誤操作を防ぐ方法config.jsonに前回のフォルダパスを保存し、次回の初期表示にする実装- 設定ファイルにJSONを選ぶ理由と、初回起動時のエラー回避(
os.path.expanduser("~"))
tkinterのfiledialogでExcelファイルを選択する【サンプルコード】
任意のフォルダからファイルを選べるようにするため、Python標準のGUIライブラリ tkinter に含まれる filedialog を使います。氏名・アドレス・会社名のデータは第1回と同じExcelファイルを使用します。
import pandas as pd
from tkinter import filedialog
import tkinter as tk
import os
def select_and_load_excel():
# 1. 小さなメインウィンドウが裏で出ないように隠す
root = tk.Tk()
root.withdraw()
# 2. ファイル選択ダイアログを表示
# filetypesでExcelファイル(.xlsx)だけを表示するように制限
file_path = filedialog.askopenfilename(
title="Excelファイルを選択してください",
filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")]
)
# 3. ファイルが選択されたかチェック
if not file_path:
print("ファイルが選択されませんでした。")
return
print(f"選択されたファイル: {file_path}")
# 4. Excelを読み込んで表示
try:
df = pd.read_excel(file_path)
# 1行ずつデータを取り出す
for index, row in df.iterrows():
name = row['氏名']
email = row['アドレス']
company = row['会社名']
print(f"データ取得成功: {company} / {name} 様 ({email})")
except Exception as e:
print(f"エラーが発生しました: {e}")
# 実行
if __name__ == "__main__":
select_and_load_excel()VS Codeなどのエディターで実行すると、Windowsでおなじみの「ファイルを開く」画面が立ち上がります。対象のExcelファイルを選んで「開く」を押し、ターミナルにExcelのデータが出力されれば成功です。
Windows標準のファイル選択画面がそのまま使えます。選んだファイルのパスは file_path に入り、pd.read_excel() で読み込めます。
コードのポイント
root.withdraw():tkinterは本来ウィンドウを作るためのライブラリなので、これがないと空の小さなウィンドウが表示されます。それを隠すための処理です。filetypesの指定:画像や音楽ファイルなど対象外のファイルを選べないように制限し、誤操作を防ぎます。
直前に開いたフォルダを記憶する:config.jsonによる設定保存
毎回ファイル選択のたびに目的のフォルダを探すのは手間です。そこで、直前に選んだ場所を記憶し、次回はその場所を初期表示する機能を追加します。設定の保存には軽量で扱いやすい JSON形式 を使います。
仕組みのイメージ
- 起動時:
config.jsonがあるか確認し、あれば前回使ったフォルダパスを読み込む - ファイル選択時:読み込んだパスを
initialdir(初期フォルダ)として開く - 選択後:新しく選んだ場所を
config.jsonに上書き保存する
import pandas as pd
from tkinter import filedialog
import tkinter as tk
import os
import json
# 設定ファイルの保存名
CONFIG_FILE = "config.json"
def load_last_path():
"""前回使用したフォルダパスを読み込む"""
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
config = json.load(f)
return config.get("last_path", os.path.expanduser("~")) # なければホームディレクトリ
return os.path.expanduser("~")
def save_last_path(file_path):
"""選択されたフォルダパスを保存する"""
folder_path = os.path.dirname(file_path)
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
json.dump({"last_path": folder_path}, f, ensure_ascii=False, indent=4)
def select_and_load_excel():
root = tk.Tk()
root.withdraw()
# 前回のパスを取得
initial_dir = load_last_path()
file_path = filedialog.askopenfilename(
title="Excelファイルを選択してください",
initialdir=initial_dir, # ここで前回の場所を指定!
filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")]
)
if not file_path:
print("ファイルが選択されませんでした。")
return
# 選択されたらパスを保存
save_last_path(file_path)
print(f"選択されたファイル: {file_path}")
try:
df = pd.read_excel(file_path)
for index, row in df.iterrows():
print(f"取得: {row['会社名']} {row['氏名']} 様")
except Exception as e:
print(f"エラー: {e}")
if __name__ == "__main__":
select_and_load_excel()実行すると前回開いたフォルダが最初に開き、ターミナルにExcelのデータが出力されます。スクリプトと同じフォルダに config.json が自動生成されていれば成功です(すでにある場合は、そのファイルから設定が読み込まれます)。
config.json の中身は {{"last_path": "選んだフォルダ"}} という単純なJSONです。テキストエディタで開いて確認できます。
設計上の工夫点
- 直前のフォルダを記憶する:毎回同じフォルダを探す手間を省き、操作回数を減らすため
- 設定ファイルにJSONを採用:テキストエディタで中身を確認しやすく、Pythonの辞書型(dict)と同じ感覚で扱えるため
os.path.expanduser("~")を初期値に使用:初回起動時など設定ファイルが無い場合でも、エラーを出さずにホームディレクトリを開けるようにするため
ファイルの配置はどうなる?
プログラムを実行すると、以下のような構成になります。config.json は初回実行時に自動生成されます。
作業フォルダ/
├── mailer.py (メインプログラム)
├── config.json (前回パスを記憶しているファイル)
└── client_list.xlsxよくある質問(tkinter filedialog・config.json)
Qfiledialog.askopenfilename() を実行すると、小さな空のウィンドウが一緒に出てしまいます
Atkinterは本来ウィンドウを作るライブラリなので、tk.Tk() で作った親ウィンドウが表示されます。root = tk.Tk() の直後に root.withdraw() を呼ぶと、この空ウィンドウを隠せます。
Qダイアログで「キャンセル」を押すとエラーになります
Aaskopenfilename() はキャンセル時に空文字(””)を返します。if not file_path: return のように、空かどうかを必ずチェックしてから読み込み処理へ進みます。
Qfiletypes を指定してもすべてのファイルが表示されます
Afiletypes=[(“Excel files”, “*.xlsx”), (“All files”, “*.*”)] のように「すべてのファイル」を含めていると、ユーザーが表示を切り替えられます。.xlsxだけに絞りたい場合は (“All files”, “*.*”) の行を外します。
Qconfig.json はどこに作られますか?別の場所に保存したいです
Aコードでは CONFIG_FILE = “config.json” と相対パスで指定しているため、スクリプトを実行したカレントディレクトリに作られます。場所を固定したい場合は os.path.join(os.path.dirname(__file__), “config.json”) のように、スクリプトと同じフォルダを明示します。
Q前回のフォルダを記憶しているはずなのに、初回だけホームフォルダが開きます
A初回は config.json がまだ無いため、load_last_path() が os.path.expanduser(“~”)(ホームディレクトリ)を返す設計です。一度ファイルを選ぶと config.json が生成され、次回からはそのフォルダが初期表示されます。
Follow me on X
本ブログの中の人「ニンジン🥕」はXやってます。新着記事はいち早くポストでお知らせしているので、見逃したくない方は @ninjin_py_vba をフォローしてみてください🥕
@ninjin_py_vba をフォローシリーズ記事一覧
電子工作・自動化ツールの製作記録をシリーズごとにまとめています。気になるテーマからお読みください。
-
FILE.01 — IoT
Raspberry Pi Pico W × GASラズパイPico W×GASで自作!「LINEで動く温湿度&スマートリモコン」完全ロードマップ
「外出中のペットの室温が心配…」そんな思いからスタートしたIoT自作プロジェクトの総集編。温湿度監視からエアコン遠隔操作まで、仕組みをゼロから作りたい方のための全5回の開発記録です。
シリーズを読む -
FILE.02 — CNC
Arduino × レーザー刻印CNCCNC自作シリーズ
高精度な加工を目指し、本格的な自作CNC製作に挑戦中。現在は基幹パーツであるオリエンタルモーターの納品を待つ「設計・準備編」を公開。ハードとソフトの両面から、理想のマシンを形にする過程をリアルタイムにお届けします。
シリーズを読む -
FILE.03 — XY軸制御
Raspberry Pi × ステッピングモーターXYテーブルシリーズ
Raspberry Piとステッパモーターを使い、ゼロから2軸制御に挑む記録。OS設定から回路設計、多軸制御のPythonコードまで、躓きやすいポイントを徹底図解。電子工作初心者が「動く感動」を味わうための実戦ガイドです。
シリーズを読む -
FILE.04 — 業務自動化
Python × Excel × CustomTkinter【Python開発記】NINJIN Mail制作記
PythonとExcelを連携させ、実務で即戦力となるメール送信ツールを開発。CustomTkinterによるUI構築や、ミスを防ぐテンプレート活用術など、現場の「痒い所に手が届く」自動化ノウハウを細部まで丁寧に解説します。
シリーズを読む -
FILE.05 — 業務自動化
Python × Excel × GUIアプリ化Invoice Maker(請求書・見積書自動作成)
手作業の請求書作成から卒業!PythonでExcelデータを読み込み一括PDF化する「Invoice_Maker」の作り方を全3回で解説。基本ロジックからGUIアプリ化まで、実務で役立つ自動化ノウハウが満載です。
シリーズを読む




コメント