🦆

PySimpleGUI 入門 (1)

2024/07/12に公開

PySimpleGUI 入門 (1)

PySimpleGUI は Python で GUI アプリを作るときに便利なライブラリです。

PySimpleGUI の基本的な使い方については、PySimpleGUI 入門 (PDF) という網羅的で優れた入門記事があるのでそれを参考にして下さい。

有償化の話

PySimpleGUI は version 5 から有償化されたようですが、ホビーユースで個人で使う分には無料で使えるようです。(登録ページから登録してみたら、なんか1年有効なライセンスキーが入手できました。画面表示と、メール送信があります。)

$ pip3 install --upgrade PySimpleGUI
Requirement already satisfied: PySimpleGUI in /Users/miyamoto/miniconda3/lib/python3.11/site-packages (4.60.5)
Collecting PySimpleGUI
  Downloading PySimpleGUI-5.0.6-py3-none-any.whl.metadata (6.6 kB)
Requirement already satisfied: rsa in /Users/miyamoto/miniconda3/lib/python3.11/site-packages (from PySimpleGUI) (4.9)
Requirement already satisfied: pyasn1>=0.1.3 in /Users/miyamoto/miniconda3/lib/python3.11/site-packages (from rsa->PySimpleGUI) (0.5.1)
Downloading PySimpleGUI-5.0.6-py3-none-any.whl (1.0 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.0/1.0 MB 3.4 MB/s eta 0:00:00
Installing collected packages: PySimpleGUI
  Attempting uninstall: PySimpleGUI
    Found existing installation: PySimpleGUI 4.60.5
    Uninstalling PySimpleGUI-4.60.5:
      Successfully uninstalled PySimpleGUI-4.60.5
Successfully installed PySimpleGUI-5.0.6
$ python3
Python 3.11.5 (main, Sep 11 2023, 08:31:25) [Clang 14.0.6 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import PySimpleGUI as sg

ライブラリをインポートすると、初回だけ次のような画面が出ます。

Agreement にチェックつけて OK すると、ライセンスキーを入力すると、こんな画面が出て使えるようになります。

チュートリアル

https://docs.pysimplegui.com/en/latest/cookbook/ecookbook/ に載っているチュートリアルをやってみます。

import PySimpleGUI as sg

sg.theme('Dark Amber')  # Let's set our own color theme

# STEP 1 define the layout
layout = [ 
            [sg.Text('This is a very basic PySimpleGUI layout')],
            [sg.Input()],
            [sg.Button('Button'), sg.Button('Exit')]
         ]

#STEP 2 - create the window
window = sg.Window('My new window', layout)

# STEP3 - the event loop
while True:
    event, values = window.read()   # Read the event that happened and the values dictionary
    print(event, values)
    if event == sg.WIN_CLOSED or event == 'Exit':     # If user closed window with X or if user clicked "Exit" button then exit
      break
    if event == 'Button':
      print('You pressed the button')
window.close()

こんな感じの画面が表示されます。

UI をコードで定義するのが PySimpleGUI の流儀みたいですが、簡単な UI ならコード以外で定義したほうが楽な気がして、軽いラッパーを書いてみました。

import yaml
import PySimpleGUI as sg

def read_yaml(filename):
  with open(filename, 'r') as y:
    return yaml.safe_load(y)

def as_window(yml, key):
  if key not in yml:
    raise KeyError(f'key={key} not found.')
  if ('title' not in yml[key]) or ('layout' not in yml[key]):
    raise ValueError(f'missing keys in window.key={key}: {list(yml[key].keys())}')
  d = yml[key].copy()
  d['layout'] = as_layout(d, 'layout')
  return sg.Window(**d)

def as_layout(yml, key):
  if key not in yml:
    raise KeyError(f'key={key} not found.')
  return [[trans_element(e) for e in row] for row in yml[key]]

def trans_element(e):
  if len(e.keys()) != 1:
    raise ValueError(f'#keys != 1: {e}')
  k = list(e.keys())[0]
  match k:
    case 'Text' | 'T':
      return as_text(e[k])
    case 'Input' | 'I':
      return as_input(e[k])
    case 'Button' | 'B':
      return as_button(e[k])
    case _:
      raise KeyError(f'KeyError: {e}')

def as_text(d):
  if d is None:
    return sg.Text()
  elif '_' in d:
    s = d['_']
    del d['_']
    return sg.Text(s, **d)
  else:
    return sg.Text(**d)
  
def as_input(d):
  if d is None:
    return sg.Input()
  elif '_' in d:
    s = d['_']
    del d['_']
    return sg.Input(s, **d)
  else:
    return sg.Input(**d)

def as_button(d):
  if d is None:
    return sg.Button()
  elif '_' in d:
    s = d['_']
    del d['_']
    return sg.Button(s, **d)
  else:
    return sg.Button(**d)

先のコードを

yml = read_yaml('test.yml')
window = as_window(yml, 'window')

と修正し、

test.yml として

window:
  title: My new window
  layout:
    - - Text:
          _: 'This is a very basic PySimpleGUI layout'
    - - Input:
    - - Button:
          _: 'Button'
      - Button:
          _: 'Exit'

と定義します(最後に空行が1行必須)。

これでも同じように動きました。

追記:
この YAML ラッパーをもうちょっと改良した、という話をPySimpleGUI 入門 (2) に書きました。

Discussion