PySimpleGUIモジュールを使用すると、Tkinterを使用するよりも簡単にPythonのGUIプログラムを作成することが出来るようなので、実際にPySimpleGUIモジュールインストールして、以前の記事「Pythonのお勉強:OpenPyXLでPDFファイルのリスト(EXCEL)を作成する」で作成したプログラムをGUIで実行できるようにしてみました。
PySimpleGUIのインストール
PySimpleGUIモジュールは、以下のpipコマンドで簡単にインストールできました。
% pip install PySimpleGUI Collecting PySimpleGUI : Successfully installed PySimpleGUI-4.60.4 |
PySimpleGUIのテンプレートプログラム
PySimpleGUIのイベントによる動作を確認するために、PySimpleGUIモジュールを使用したPythonのGUIプログラムのテンプレートプログラムを作成しました。
- 「PySimpleGUI_Template.py」
import PySimpleGUI as sg
import sys
def event_Submit(root_dir):
#
# PDFリストのEXCELファイルを作成する処理を書く
#
yes_no_ans = sg.popup_yes_no('ルートフォルダ \n[ ' + root_dir + ' ]'+'\n 以下にあるPDFファイルのリスト(EXCEL)を作成しました。\n\nプログラムを終了しますか?\n',title='<YES/NO>確認ダイアログ')
if yes_no_ans == "Yes":
sys.exit()
def main():
layout = [
[sg.Text('[1] PDFのルートフォルダを選択', size=(40, 1))],
[sg.Input(default_text='', size=(50,2)),sg.FolderBrowse()],
[sg.Text('[2] PDFリストのEXCELファイルを作成', size=(44, 2)),sg.Submit(key="btn_Submit")],
[sg.Text('[3] プログラムの終了', size=(44, 2)),sg.Cancel(key="btn_Cancel")]]
window = sg.Window('PDFリストのEXCELファイル作成', layout=layout)
while True:
event, value = window.read()
if event is None:
break
# keyの文字列を判定してイベント処理を分岐
elif event == "btn_Submit":
if not value[0]:
sg.popup('最初にPDFのルートフォルダを選択してください.')
else:
root_dir=value[0]
event_Submit(root_dir)
elif event == "btn_Cancel":
break
else:
continue
window.close()
if __name__ == "__main__":
main()
テンプレートプログラムから得られた知見
- PySimpleGUIモジュールをインポートする際には、以下のように「sg」という名前を付けてインポートすることが推奨されている。
import PySimpleGUI as sg
- Windowsオブジェクトの生成は、以下のように「sg.Window()」にタイトル名とウィジットのリスト(layout)を指定して行う。
window = sg.Window('PDFリストのEXCELファイル作成', layout=layout)
- ウィジットのリスト(layout)は、以下のように実際の画面レイアウトに合わせてウィジットを配置して作成する。
layout = [
[sg.Text('[1] PDFのルートフォルダを選択', size=(40, 1))],
[sg.Input(default_text='', size=(50,2)),sg.FolderBrowse()],
[sg.Text('[2] PDFリストのEXCELファイルを作成', size=(44, 2)),sg.Submit(key="btn_Submit")],
[sg.Text('[3] プログラムの終了', size=(44, 2)),sg.Cancel(key="btn_Cancel")]]
- 「sg.InputText() 」と 「sg.FolderBrowse()」 以下のように横に並べて記載すると、フォルダ選択用のGUIを作成することが出来る。
[sg.Input(default_text='', size=(50,2)),sg.FolderBrowse()],
「sg.FolderBrowse()」を「sg.FileBrowse()」に変更するとファイル選択用のGUIを作成することが出来る。
- イベントで発生する値は、「while True:」の無限ループでwindow.read()のイベント発生を待ち、イベントが発生したらタプル形式(key, value)でイベントを受け取る。
while True:
event, value = window.read()
- イベント(Key)の文字列をif文で判定して処理を分岐する。
if event is None:
break
elif event == "btn_Submit":
if not value[0]:
sg.popup('最初にPDFのルートフォルダを選択してください.')
else:
root_dir=value[0]
event_Submit(root_dir)
elif event == "btn_Cancel":
break
else:
continue
- ウィンドウ画面の「閉じる(X)」ボタンがクリックされると、イベント(Key)として「None」が返ってくるので、「break」してプログラム終了をする。
if event is None:
break
- value[0]には、sg.Input()の文字列(root_dir)が格納される。value[0]に格納された文字列が「空白・NULL」の場合は、「sg.popup()」で注意メッセージを表示する。
if not value[0]:
sg.popup('最初にPDFのルートフォルダを選択してください.')
- value[0]に格納されたroot_dirの文字列が「空白・NULL」以外の場合は、変数「root_dir」にvalue[0]の値を代入し、「root_dir」を引数にしてevent_Submit()関数を呼び出す。
else:
root_dir=value[0]
event_Submit(root_dir)
- 「Cancel」ボタンがクリックされると、イベント(Key)として指定した「btn_Cancel」が返ってくるので、「break」してプログラム終了をする。
elif event == "btn_Cancel":
break
ディレクトリを再帰的に探索するGUIサンプルプログラム(「PSG_Pdf_DirList.py」)
以前の記事「Pythonのお勉強:OpenPyXLでPDFファイルのリスト(EXCEL)を作成する」で作成したプログラムをGUIで実行できるようにしたサンプルプログラムを以下に記載します。
- 「PSG_Pdf_DirList.py」
on"]
import PySimpleGUI as sg
import sys
import os
import os.path
import fnmatch
import openpyxl
from openpyxl.styles.alignment import Alignment
from openpyxl.styles import PatternFill
from openpyxl.styles import Font
def event_Submit(root_dir):
# 変数定義
search_dir = root_dir
dirname_lst = list() # ディレクトリ名の格納用リスト
pdfname_lst = list() # PDFファイル名の格納用リスト
lnkname_lst = list() # HYPERLINK用ファイル名の格納用リスト
maxlen_dirname = 0 # ディレクトリ名の最大バイト数格納用変数
maxlen_pdfname = 0 # PDFファイル名の最大バイト数格納用変数
maxlen_lnkname = 0 # HYPERLINK用ファイル名の最大バイト数格納用変数
# 新規ワークブックの作成
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "pdf_list"
# PDFファイル名とHYPERLINK用ファイル名をリストに格納
for dirpath, dirs, files in os.walk(search_dir):
for fname in files:
if fnmatch.fnmatch(fname, '*.pdf'):
# ディレクトリ名をリストに格納
# print(dirpath)
dirname = dirpath
dirname_lst.append(dirname)
if len(dirname.encode()) > maxlen_dirname:
maxlen_dirname = len(dirname.encode())
# PDFファイル名をリストに格納
# print(fname)
pdfname = fname
pdfname_lst.append(pdfname)
if len(pdfname.encode()) > maxlen_pdfname:
maxlen_pdfname = len(pdfname.encode())
# HYPERLINK用ファイル名をリストに格納
# print(os.path.join(dirpath, fname))
lnkname = os.path.join(dirpath, fname)
lnkname_lst.append(lnkname)
if len(lnkname.encode()) > maxlen_lnkname:
maxlen_lnkname = len(lnkname.encode())
start_row = 1 # EXCEL表示開始列
start_col = 1 # EXCEL表示開始行
# タイトルセルの名前を設定
ws.cell(start_col,start_row).value='ディレクトリ名'
ws.cell(start_col,start_row+1).value='PDFファイル名'
# タイトルセルの表示幅を変更
ws.column_dimensions['A'].width = maxlen_dirname
ws.column_dimensions['B'].width = maxlen_pdfname
# タイトルセル('A1':'B1')の背景色を変更 「fil_obj(水色 塗り潰し)」
fil_obj = PatternFill(fgColor='00ffff' , patternType='solid')
for rows in ws['A1':'B1']:
for cell in rows:
cell.fill = fil_obj
# セルにファイル名を書き込む
for i in range(0,len(pdfname_lst)):
# 現在の行(cur_col)と列(cur_row)を変数に格納
cur_col = i+start_col+1
cur_row = start_row
# シート'A'列にディレクトリ名を書き込む
hdir_name = dirname_lst[i]
hdir_str = hdir_name
ws.cell(cur_col,cur_row).value = hdir_name
ws.cell(cur_col,cur_row).hyperlink = hdir_str
# シート'B'列にPDFファイル名とHYPERLINKを書き込む
hpdf_name = pdfname_lst[i]
hlnk_name = lnkname_lst[i]
hlnk_str = hlnk_name
ws.cell(cur_col,cur_row+1).value = hpdf_name
ws.cell(cur_col,cur_row+1).hyperlink = hlnk_str
# ハイパーリンクの書式設定 fnt_obj(色:青 シングルアンダーライン)
fnt_obj = Font(color='0000FF', u='single')
ws.cell(cur_col,cur_row).font = fnt_obj
ws.cell(cur_col,cur_row+1).font = fnt_obj
# シートセル全体の水平方向を左寄せ、高さ方向を中央揃え
for col in ws:
for cell in col:
cell.alignment = Alignment(horizontal='left',vertical='center')
# シートセルの行高さ変更
for i in range(len(dirname_lst)+2):
ws.row_dimensions[i].height = 21
# 作成したファイルをに名前をつけて保存
save_filename = 'Pdf_DirList.xlsx'
while True:
try:
wb.save(filename = save_filename)
except PermissionError:
sg.popup_ok('Excelファイルが開いていますので閉じてください。',title='エラーメッセージ')
else:
break;
wb.close()
yes_no_ans = sg.popup_yes_no('ルートフォルダ \n[ ' + root_dir + ' ]'+'\n にあるPDFファイルのリスト(EXCEL)を作成しました。\n\nプログラムを終了しますか?\n',title='<YES/NO>確認ダイアログ')
if yes_no_ans == "Yes":
sys.exit()
# メイン
def main():
layout = [
[sg.Text('[1] PDFのルートフォルダを選択', size=(40, 1))],
[sg.Input(default_text='', size=(50,2)),sg.FolderBrowse()],
[sg.Text('[2] PDFリストのEXCELファイルを作成', size=(44, 2)),sg.Submit(key="btn_Submit")],
[sg.Text('[3] プログラムの終了', size=(44, 2)),sg.Cancel(key="btn_Cancel")]]
window = sg.Window('PDFリストのEXCELファイル作成', layout=layout)
while True:
event, value = window.read()
if event is None:
break
# keyの文字列を判定してイベント処理を分岐
elif event == "btn_Submit":
if not value[0]:
sg.popup('最初にPDFのルートフォルダを選択してください.')
else:
root_dir=value[0]
event_Submit(root_dir)
elif event == "btn_Cancel":
break
else:
continue
window.close()
if __name__ == "__main__":
main()
サンプルプログラム(「PSG_Pdf_DirList.py」)のGUI動作概要
最後に、サンプルプログラムのGUI動作概要を以下に記載します。
- VSCodeでデバック無しで実行すると以下のウィンドウが表示されます。
- 「[1] PDFのルートフォルダを選択」横の「Brows」ボタンをクリックすると、システムの「フォルダ選択ダイアログ」が表示されます。選択したルートフォルダのPATHが「sg.Input()の値」として設定されます。
- 「[2] PDFリストのEXCELファイルを作成」横の「Submit」ボタンをクリックすると、カレントフォルダに「Pdf_DirList.xlsx」が作成されます。
- PySimpleGUIモジュールをインポートする際には、以下のように「sg」という名前を付けてインポートすることが推奨されている。
- Pdf_DirList.xlsx」が作成されると、以下のような<「<YES/NO>確認ダイアログ」が表示されます。
【ソースコード】
yes_no_ans = sg.popup_yes_no('ルートフォルダ \n[ ' + root_dir + ' ]'+'\n 以下にあるPDFファイルのリスト(EXCEL)を作成しました。\n\nプログラムを終了しますか?\n',title='<YES/NO>確認ダイアログ')
- ルートフォルダのPATH「sg.Input()の値」が「空白・NULL」の状態で「Submit」ボタンをクリックすると、以下のような「ルートフォルダ選択を促す注意メッセージ」が表示されます。
【ソースコード】
sg.popup('最初にPDFのルートフォルダを選択してください.')
実際に動作するサンプルプログラムを作成できたので、なんとなく「PySimpleGUI」の使い方が判ったような気がします。
コメント