メインコンテンツへスキップ
見出し画像

マイブームPySimpleGUIを紹介

    # Pythonにおける他のGUIについて

    以下はあくまで個人的な印象

    tkinter
    ・標準だからすぐ使える&入門記事や本が多い
    ・ドキュメントが雑(event_generateとかは全然書いてない)
    ・作り込もうとすると元のTcl/Tkを知る必要有り
    ・コード量が多い
    ・配置が大変
    PySimpleGUI
    ・pip3 install pysimplegui で使える
    ・[ドキュメント]が本当にしっかりしている(cookbookなるページあり)
    ・コード量が少ない(短縮名がある)
    ・配置が楽(リストとして記述できる)

    以下を見れば簡単なものはサクッと作るように説明。ところどころ公式サイトのレシピプログラムを用いながら。

    # ウィンドウの実装方法は2つ

    ## ワンショットウィンドウ

    ワンショットウィンドウ はポップアップのようなもの。
    1回OKボタンを押すとそのウィンドウは閉じる。次の工程では新しいウィンドウが出てくる。

    以下は公式サイトのcookbookによるプログラム

    import PySimpleGUI as sg
    
    layout = [
       [sg.Text("My one-shot window.")],
       [sg.InputText(key="-IN-")],
       [sg.Submit(), sg.Cancel()],
    ]
    
    window = sg.Window("Window Title", layout)
    
    event, values = window.read()
    window.close()
    
    text_input = values["-IN-"]
    sg.popup("You entered", text_input)

    hogehogeと入力してSubmitボタンを押すと、

    画像1

    最初のウィンドウが消えて新しいウィンドウ(ポップアップウィンドウ)が出てくる。

    画像2

    プログラムを見てみる。ウィジェットは "layout" のようにリストで並べることができる。Windowクラスのread()の1つ目の返り値がどんなイベントが起こったかを返す。
    2つ目の返り値は辞書で、入力系の値はこれに入る。sg.InputText(key="-IN-")  のようにしてキーを指定。辞書なので、入力した値を出すときは values["-IN-"]。
    もちろん、キーを指定しなくても自動で0から番号が付与される。番号の場合は、values[0]のように指定できる。
    また、ButtonはButtonに表示させる文字列、TextはTextに表示させる文字列がキーになる。

    ポップアップウィンドウの詳しい説明についてはここ)。Buttonはここ。

    ## 持続的ウィンドウ

    持続的ウィンドウ は、ソフトウェアとかのように、1つのウィンドウの中で画面が遷移していくもの。たぶんこっちが主流。

    以下は公式サイトのcookbookによるプログラム

    import PySimpleGUI as sg
    
    sg.theme("BluePurple")
    
    layout = [
       [sg.Text("Your typed chars appear here:"), sg.Text(size=(15, 1), key="-OUTPUT-")],
       [sg.Input(key="-IN-")],
       [sg.Button("Show"), sg.Button("Exit")],
    ]
    
    window = sg.Window("Pattern 2B", layout)
    
    while True:  # Event Loop
       event, values = window.read()
       print(event, values)
       if event in (None, "Exit"):
           break
       if event == "Show":
           # "-OUTPUT-" 要素を "-IN-" 要素の値に更新
           window["-OUTPUT-"].update(values["-IN-"])
    
    window.close()

    最初のウィンドウでhogeと入力してShowボタンを押すと、

    画像3

    同じウィンドウのまま画面が更新される。1行目に hoge と表示されていることがわかる。

    画像4

    プログラムを見てみる。今度は一度イベントが発生しても、whileループによって繰り返されている。画面の更新はupdateメソッドによって行われる。

    コードを短くするために、ButtonをB、TextをT やTxtと書くこともできる。

    # テーマの変更

    sg.theme() でテーマを変更できる。テーマの一覧は

    import PySimpleGUI as sg
    sg.preview_all_look_and_feel_themes()

    または

    import PySimpleGUI as sg
    
    """
       PySimpleGUIのテーマをPySimpleGUIを使って確認することができます。
       いずれかのテーマ名をクリックすると、選択したテーマを使用したウィンドウが出ます。
    """
    
    sg.theme('Dark Brown')
    
    layout = [[sg.Text('Look and Feel Browser')],
             [sg.Text('Click a look and feel color to see demo window')],
             [sg.Listbox(values=sg.theme_list(),
                         size=(20, 12), key='-LIST-', enable_events=True)],
             [sg.Button('Exit')]]
    
    window = sg.Window('Look and Feel Browser', layout)
    
    while True:  # Event Loop
       event, values = window.read()
       if event in (None, 'Exit'):
           break
       sg.theme(values['-LIST-'][0])
       sg.popup_get_text('This is {}'.format(values['-LIST-'][0]))
    
    window.close()

    で見ることができる(詳しくは公式サイトのここらへんかここらへん)。後者のほうがオススメ。以下の画像のように、リストから選択できる。

    画像5

    テーマは自作や修正が可能。タイトルバーを消したりいろいろできる。

    # コマンドラインの引数で動作を変えるレシピ

    コマンドラインで実行する際に、引数にファイル名が入るとする。このときに、引数があればそれをファイル名とし、なければGUIでファイルブラウザーを開いてファイル名を引っ張ってこれる。そんなレシピがあった。

    import PySimpleGUI as sg
    import sys
    
    if len(sys.argv) == 1:
       event, values = sg.Window('My Script',
                       [[sg.Text('Document to open')],
                       [sg.InputText(), sg.FileBrowse()],
                       [sg.Open(), sg.Cancel()]]).read(close=True)
       fname = values[0]
    else:
       fname = sys.argv[1]
    
    if not fname:
       sg.popup("Cancel", "No filename supplied")
       raise SystemExit("Cancelling: no filename supplied")
    else:
       sg.popup('The filename you chose was', fname)

    これはもうそのまま自分のプログラムに追加できそう。

    FileBrowse は下の画像では"Browse"となっていて、これを押すとファイル選択ダイアログがでてくる。そこでファイルを選択すると、

    画像6

    前に配置されている Input にテキストが挿入されている。

    画像7

    このプログラムでは、InputText と FileBrowse については、特に値のやり取りを指定したわけではない。これは、FileBrowse のようなボタンには、"ターゲット"(Button ElementのButton targets 参照)があるから。

    ターゲットはデフォルトで、一つ左のText や InputText 要素を指す。

    つまり、InputText と FileBrowse を隣同士で配置するだけで、FileBrowse で取得したファイル名が自動でInputTextに挿入される。

    もちろん以下のように、InputText にキー、FileBrowseにそのキーをターゲットとして指定すれば、値のやり取りが可能。

    layout = [[sg.T('Source Folder')],
                     [sg.In(key='input')],
                     [sg.FolderBrowse(target='input'), sg.OK()]]

    # コールバックの実装

    公式サイトより以下のようにコールバックを実装することができる。

    import PySimpleGUI as sg
    
    sg.theme("Light Blue 3")
    # このデザインパターンは、ボタンのコールバックのシミュレート
    # この実装は、単純な辞書を使ってイベントと関数を格納する
    
    
    # コールバック関数
    def button1():
       print("Button 1 callback")
    
    
    def button2():
       print("Button 2 callback")
    
    
    # 関数を呼び出すボタンの対応を記した辞書
    dispatch_dictionary = {"1": button1, "2": button2}
    
    # GUIのデザインをレイアウト
    layout = [
       [sg.Text("Please click a button", auto_size_text=True)],
       [sg.Button("1"), sg.Button("2"), sg.Button("3"), sg.Quit()],
    ]
    
    # ユーザーにウィンドウを表示
    window = sg.Window("Button callback example", layout)
    
    # Event loop. ボタンを読んでコールバックする
    while True:
       # ウィンドウを読み取る
       event, value = window.read()
       if event in ("Quit", None):
           break
       # 発生したイベントが関数を書いた辞書にあるか調べる
       if event in dispatch_dictionary:
           func_to_call = dispatch_dictionary[event]
           func_to_call()
       else:
           print("Event {} not in dispatch dictionary".format(event))
    
    window.close()
    
    # All done!
    sg.popup_ok("Done")

    画像8

    まず、Button を作成するときの名前(=Buttonのキー)と関数名を対応させた辞書(ここではdispatch_dictionary)を用意する。whileの中で発生したイベントが辞書に有るかを調べて、存在すれば呼ぶ。

    # プログレスメーター

    1行でプログレスメーターが書ける!

    公式サイト曰く、他のPythonパッケージは複数行で書かねばならないこと、ループの外でも書く必要がある とのこと。非常に直感的だなぁ。詳しい情報はここ。

    import PySimpleGUI as sg
    
    sg.theme('Dark Blue 8')
    
    for i in range(1000):   # this is your "work loop" that you want to monitor
       sg.OneLineProgressMeter('One Line Meter Example', i + 1, 1000, 'key')

    画像9

    # プログレスバー

    プログレスバーもあります。以下は公式サイトのカスタマイズについてのプログラム。

    import PySimpleGUI as sg
    
    layout = [
       [sg.Text("A custom progress meter")],
       [sg.ProgressBar(1000, orientation="h", size=(20, 20), key="progbar")],
       [sg.Cancel()],
    ]
    
    window = sg.Window("Custom Progress Meter", layout)
    for i in range(1000):
       event, values = window.read(timeout=0)
       if event == "Cancel" or event is None:
           break
       window["progbar"].update_bar(i + 1)
    
    window.close()

    画像10

    # レイアウトの記述の注意点

    PySimpleGUIではレイアウトをリストで書ける。しかし、blackなどのフォーマットをかけると、せっかくきれいに書いたリスト構造がかえって見にくくなってしまう。

    こんなときは、

    # fmt:off
    layout = [[hogehoge]]
    # fmt:on

    のような部分的にフォーマットをオフにするコメントアウトを用いると良い(例はblackでのオンオフ)。

    # その他

    公式のドキュメント、デモプログラム等は以下。

    http://PySimpleGUI.org
    http://calls.PySimpleGUI.org
    http://Cookbook.PySimpleGUI.org
    http://Demos.PySimpleGUI.org
    http://Trinket.PySimpleGUI.org
    http://YouTube.PySimpleGUI.org
    http://PySimpleGUI.com

    PySimpleGUIの他の記事は以下。


    この記事が参加している募集

    あなたへのおすすめ