この記事を読んでできるもの
PySimpleGUIを使用して、ファイル、フォルダをダイアログを使ってファイルを取得、
取得したファイルを使用して処理を実行、ログを画面にすることができます
概要
脱VBAとしてPythonを使用している記事や本がちらほらあり、Excelファイルの操作にOpenPyXl を使用している記事はありますが、ファイルの起動に関してはCLIのものがほとんどでGUIで操作する記事はあまり見かけません。
今回はVBAのGUI相当のものをPySimpleGUIで行う説明を行います。
PySimpleGUIの基本的な操作についてはTkinterを使うのであればPySimpleGUIを使ってみたらという話を参考にしてください。
例えばエクセルで複数ファイルを読み込んで1ファイルにまとめる操作を行う場合には以下の動作および表示が必要かとと思います。
- ファイルを複数選択して読み込む
- 選択したファイル一覧を表示
- オプションの選択
- 実行
- 実行結果のログ出力
コードにすると以下の内容になります。なお今回はエクセル操作の機能は載せていません。
あくまでもGUI部分の説目のみになります。
# 元のファイル https://pysimplegui.trinket.io/demo-programs#/examples-for-reddit-posts/visual-basic-mockup
import PySimpleGUI as sg
from os.path import basename
frame1 = [[sg.Radio('1ファイルにシートごとにまとめる', 1, key='-MULTI-SHEET-', default=True)],
[sg.Radio('1ファイル1シートにまとめる', 1, key='-ONE-SHEET-')]]
col1 = [[sg.Button('実行')],
[sg.Button('終了')]]
layout = [[sg.Text('ファイル選択', size=(15, 1), justification='right'),
sg.InputText('ファイル一覧', enable_events=True,),
sg.FilesBrowse('ファイルを追加', key='-FILES-', file_types=(('Excell ファイル', '*.xlsx'),))],
[sg.Button('ログをコピー'), sg.Button('ログをクリア')],
[sg.Output(size=(100, 5), key='-MULTILINE-')],
[sg.Button('入力一覧をクリア')],
[sg.Listbox([], size=(100, 10), enable_events=True, key='-LIST-')],
[sg.Frame('処理内容', frame1), sg.Column(col1)]]
window = sg.Window('エクセルの結合', layout)
new_files = []
new_file_names = []
while True: # Event Loop
event, values = window.read()
if event in (None, '終了'):
break
if event == '実行':
print('処理を実行')
print('処理対象ファイル:', new_files)
# ラジオボタンの値によって処理が変わる
if values['-MULTI-SHEET-']:
print('複数シートを1ファイルにまとめる')
elif values['-ONE-SHEET-']:
print('複数シートを1シートにまとめる')
# ポップアップ
sg.popup('処理が正常終了しました')
elif event == 'ログをクリア':
print('ログをクリア')
window.FindElement('-MULTILINE-').Update('')
elif event == 'ログをコピー':
window.FindElement('-MULTILINE-').Widget.clipboard_append(window.find_element('-MULTILINE-').Get())
sg.popup('ログをコピーしました')
elif event == '入力一覧をクリア':
print('入力一覧をクリア')
new_files.clear()
new_file_names.clear()
window['-LIST-'].update('')
elif values['-FILES-'] != '':
print('FilesBrowse')
# TODO:実運用には同一ファイルかどうかの処理が必要
new_files.extend(values['-FILES-'].split(';'))
new_file_names.extend([basename(file_path) for file_path in new_files])
print('ファイルを追加')
window['-LIST-'].update(new_file_names) # リストボックスに表示します
window.close()
以下それぞれの機能のついての紹介です
ファイルを複数選択して読み込む
PySimpleGUIでファイルを指定するには以下の3つのボタン(メソッド)があります。
- FolderBrowse()
- フォルダを読み込み
- FileBrowse()
- ファイルを一つ読み込む
- FilesBrowse()
- 複数ファイルを一つ読み込む
動作的には、レイアウトに追加するとボタンが表示される、クリックするとダイアログが表示される、ダイアログ内で選択したファイルが表示されます。
選択したファイルは絶対パスで取得できます。
以下コードの例です。なお今回のコードは公式のVisual Basic Mockupを参考に機能追加を加えています。
import PySimpleGUI as sg
sg.InputText('ファイル一覧',enable_events=True,), sg.FilesBrowse('ファイルを追加', key='-FILES-', file_types=(("Excell ファイル", "*.xlsx"),))],
FilesBrowse
で複数ファイルを取得した場合は、値は「ファイル1の絶対パス;ファイルの絶対パス;」となっています。values['-FILES-'].split(';'))
というようにするとファイルを分割して取得できます
ドラッグ&dドロップについて
Pythonに付属しているtkinterにはドラッグ&ドロップの機能は標準ではついていません。
自分で拡張機能をインストールするとできるようになるようです。
PySimpleGUIはtkinterのラッパーですのでドラッグ&ドロップの機能はないです。
ただPythonの3.9のドキュメントを見ると以下のページがあるので次期バージョンの3.9では
Python付属のtkinterでもドラッグ&ドロップができるようになってPySimpleGUIでドラッグ&ドロップが機能追加されるようになるかもしれません
2020/2/6更新 公式に教えてもらいました。tkinterのドラッグ&ドロップはアプリ内のドラッグ&ドロップのみ対応だそうです。
エクスプローラーのドラッグ&ドロップに関してはPySimpleGUIQtが対応しているとのことでした。
# 選択したファイル一覧を表示 選択したファイルを一覧表示するのに、今回はリストボックスを使って表示します。 PySimpleGUIでは`Listbox()`を使って表示します。I think the tkinter drag and drop support is only within the application. I don't see how you can drag and drop a file from Windows explorer for example, which is the most likely source of a drag and drop.
— PySimpleGUI (@PySimpleGUI) February 15, 2020
It's supported in PySimpleGUIQt for the Input and Multiline elements.
[sg.Listbox([], size=(100, 10), enable_events=True, key='-LIST-')],
入力された内容をリストボックスにするにはwindow
クラスのupdate()
メソッドを使いっ更新を行います
window['-LIST-'].update(new_file_names) # リストボックスに表示します
オプションの選択
オプションの選択にはラジオボタンを使って実装しています。
frame1 = [[sg.Radio('1ファイルにシートごとにまとめる',1, key='-MULTI-SHEET-', default=True)],
[sg.Radio('1ファイル1シートにまとめる', 1, key='-ONE-SHEET-')]]
実行時にラジオボタンのどの値が選択されているかはkey
に設定してる値がTrue
かどうかで判定しています。
if values['-MULTI-SHEET-']:
print('複数シートを1ファイルにまとめる')
elif values['-ONE-SHEET-']:
print('複数シートを1シートにまとめる')
実行結果のログ出力
画面に実行内容を表示するにはOutput()
エレメントを使います。これを配置するとprint()
で記載した内容が出力されます
[sg.Output(size=(100,5), key='-MULTILINE-'),],
クリップボードにコピー
クリップボード関連はtkinterの以下のメソッドを使用します
-
widget.clipboard_get()
- クリップボードに格納している値を取得します。
-
widget.clipboard_clear()
- クリップボードの内容を削除します。
-
widget.clipboard_append()
- クリップボードに値を追加します。
今回はclipboard_append
を使ってOutput()
に出力されたログの値をコピーします。
window.FindElement('-MULTILINE-').Widget.clipboard_append( window.FindElement('-MULTILINE-').Get())
まとめ
PySimpleGUIでVBA相当のGUIを作る方法を紹介してみました。
ファイルをダイアログを開いて選択する。選択したファイルに処理を行うことができるGUIは応用が利くかと思います。