at backyard

Color my life with the chaos of trouble.

PySimpleGUIを触ってみた備忘録(ボタンの配置とログ出力のサンプル、テーマカラーについて)

PySimpleGUIというPythonでかんたんにGUIを作れるライブラリを触ってみたので備忘録。

github.com

目次

PySimpleGUIとは?

2018年に作成された比較的新しいライブラリで、tkinter, Qt, WxPython, RemiなどのGUIフレームワークを、よりシンプルなインターフェースに変換して利用できるライブラリ。
つまりGUIフレームワークのラッパー的な立ち位置となる。

ラッパーという立ち位置からも想像できるようにPySimpleGUIを使えば、GUIフレームワークを使ってゴリゴリUIを作成するよりもかんたんにGUIが構築できる。またpip経由でインストールが可能、というのも楽なポイント。

勿論、UIを作る用途によっては適さないシーンもあるようなので、作成するUIにそこまでこだわりはなく、ある程度工数をかけずにPythonGUIを構築したいという用途が一番マッチするような印象。

実際インストールはかんたんで、下記のようにpipインストールし、

pip install pysimplegui

公式ページにある、かんたんなサンプルを入力することで問題なくGUIが立ち上がった。

import PySimpleGUI as sg

sg.theme('DarkAmber')   # Add a touch of color
# All the stuff inside your window.
layout = [  [sg.Text('Some text on Row 1')],
            [sg.Text('Enter something on Row 2'), sg.InputText()],
            [sg.Button('Ok'), sg.Button('Cancel')] ]

# Create the Window
window = sg.Window('Window Title', layout)
# Event Loop to process "events" and get the "values" of the inputs
while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == 'Cancel': # if user closes window or clicks cancel
        break
    print('You entered ', values[0])

window.close()

なお、筆者の環境はM1 Macであり、Pyenvを用いた上で構築している Python 3.9.6 で動作している。

※m1 macでのpyenv環境構築については下記に書いたので興味ある方はぜひ

shinshin86.hateblo.jp

GUI周りだし何かしらエラーで立ち上がらないだろうな、と期待していなかったが、いちおう問題なくGUIは立ち上がったので、これは良いかもと思った次第。

PySimpleGUIはライセンスが LGPL3.0 なので商用利用などで実行バイナリを配布する場合は注意が必要

ここで余談を挟むが、最近はVBAからPythonへの移行が増えてきているらしい。
もともとVBAで書かれていた業務アプリをPythonに移植するような感じだ。

そんな流れでかんたんなGUIを構築する際のライブラリとしてPySimpleGUIが用いられている例をいくつか見つけた。

たしかに今回触ってみたが、サクッとGUIを構築できたので、これは便利そうだと思った次第。

ただし注意点があり、PySimpleGUIはライセンスがLGPL3.0のため、例えばPySimpleGUIを含んだ状態で作成した実行バイナリを配布する場合は、ソースコードを公開しなくてはならない点に注意が必要となる

ソースコード公開を回避するためには下記のような手段を取るなど一応回避手段はあるようだが、一度ここらへんは利用を始める前に検討してみたほうが良いだろう。
(下記の手段を取る場合はユーザのPCにPython環境を構築する必要がある)

teratail.com

なお、実行バイナリを配布して利用してもらいたいケースでは残念ながらPySimpleGUIは使えないので、代替案としてtkinterなどを利用することになるかと思われる。

ちょうど今tkinterを使ったGUIプログラミングについてをあれこれとまとめているので興味ある方はこちらも参照してみてください。

shinshin86.hateblo.jp

PySimpleGUIで作成したログ表示サンプル

今回はひとまずボタンに対応する処理を動かすのと、処理の中のログを表示する窓を作ってみることにした。

また、ログの内容をクリップボードにコピーする機能と、クリアする機能も合わせてつけてみた。

サンプルのコード量としては大したことないので、たぶん私が浅い知識で解説を挟むよりも、直接コードを見てもらったほうが分かるかと思う。

PySimpleGUIをインストールした環境で、下記のコードをコピペして実行してもらえれば、こんなウィンドウが立ち上がるかと思う。

PySimpleGUIで作成したかんたんなサンプル

なお、今回テーマカラーは適用していないが、テーマを指定したい場合は4行目のコメントアウトを外して、対応したカラースキームの文字列を入力すれば適用される。

テーマカラーについては少しだけこのあとに書いている。

import PySimpleGUI as sg

# テーマカラー
# sg.theme("Default")

# メインのコントロールエリア
control_layout = [
    [sg.Button("Test Log Output")],
    [sg.Button("Close")]
]

# ログの表示・操作エリア
log_layout = [
    [sg.Button("Copy"), sg.Button("Clear")],
    [sg.Output(size=(100, 5), key="-OUTPUT-")],
]

layout = [
    [sg.Frame("Log", log_layout)],
    [sg.Frame("Main Control", control_layout)]
]

# ウィンドウを作成
window = sg.Window("PySimpleGUI Log Sample", layout)

# このループ内でイベントと入力値の処理を行う
while True:
    event, values = window.read()
    
    # ウィンドウを閉じたときはここの処理が動く
    if event == sg.WIN_CLOSED:
        break

    # Closeボタンを押したときはここの処理が動く
    # ここではサンプルとして分けているが、上の処理と同じなのでif文はまとめてOK
    if event == "Close":
        break
    
    if event == "Test Log Output":
        print("Push [Test Log Output]")

    if event == "Clear":
        window.find_element("-OUTPUT-").Update("")

    if event == "Copy":
        window.find_element("-OUTPUT-").Widget.clipboard_append(window.find_element("-OUTPUT-").Get())
        sg.popup("Log copied to Clipboard.")

window.close()

今回、律儀に if だけで区切って書いているが、elifなどで分岐させてもよいのかもしれないし、実際にそうやってサンプルを書いている方もいたので、それで良い気がする。

実際に起動すると、print関数で出力されるログがログ出力用エリアに出力されるのが分かると思う。

また、今回

event, values = window.read()

values の値を使っていないが、これはまた別にサンプルを書いてみようと思う。
(PySimpleGUIを少しずつ理解していこうと思う)

PySimpleGUIのテーマカラーについて

PySimpleGUIには様々なカラースキームが用意されており、それらの一覧は下記のコードを実行することで確認できる。

import PySimpleGUI as sg
sg.theme_previewer()

これを実行すると、下記のようなウィンドウが立ち上がる。

PySimpleGUIのテーマカラー一覧

ここで利用したいテーマカラーを sg.theme("利用したいテーマ") に入力すれば適用される。

FindElementに関するWarning

今回のサンプルを実装する上で下記のようなwarningに遭遇したので、書いておく。

FindElement という対応するkeyを取得するための関数があるが、これを使うと下記のようなwarningが出る

UserWarning: Use of FindElement is not recommended.
Either switch to the recommended window[key] format or the PEP8 compliant find_element
warnings.warn('Use of FindElement is not recommended.\nEither switch to the recommended window[key] format\nor the PEP8 compliant find_element',

** Warning - FindElement should not be used to look up elements. window[key] or window.find_element are recommended. **

エラーメッセージの通りで、FindElement ではなく find_elementを使うことでwarningは消える

下記の通り。

    if event == "Clear":
        window.FindElement("-OUTPUT-").Update("")

下記のようにすることでwarningが消える

    if event == "Clear":
        window.find_element("-OUTPUT-").Update("")

以上のようにまだ少ししか触れていないが、特に面倒なエラーにも遭遇せずに扱えたので、第一印象は良さそう。

引き続き、少しずつ触っていってみようと思う。

Effective Python良かった(余談)

ずっと家で積ん読していた Effective Python を読んだら、すごくかゆいところに手の届く内容だった。
こういうときPythonだとどう書くのが良いのか?スレッド処理はどうする?などなど、普段からコード書きながら感じていた疑問が、氷が溶けるように本を読み進めていく中で溶けていくのを感じた。

しかも今試しにチェックしてみたら、第2版がでていて、内容をパワーアップしているよう!

個人的に買ってよかったPython本の一つです。

GooglePythonを使ったさまざまなサービスを立ち上げ、Pythonを知り尽くした著者による、Pythonエキスパート必携書の改訂版です。