🦆

PySimpleGUI 入門 (3)

2024/08/04に公開

前回、YAML から画面を定義するライブラリ https://github.com/tmiya/tmiya.github.io/tree/main/python/sg_yaml を作って公開した、という話をしました。
実はちょっとだけ機能を追加して、Widget 全部に対して key=widgetのkパラメータ、value=widget自身、という dictionary も YAML 解析時に生成する様にしました。これによってイベントループからwidgetの値の修正が楽になります。

という訳で今回は実際に動くアプリを作ってみます。

一目見て分かる人は何のためのツールなのか分かると思いますが(笑)、+- のボタンを押すと能力値の値の Value とそれに必要な割り振りポイントの Point の数字が上下します。利用可能な割り振りポイントを過不足なく全部割り振ると能力値が決定出来るというものです。

コードは、https://github.com/tmiya/tmiya.github.io/blob/main/python/sg_yaml/attributes.py にあります。実行は $ python3 attributes.py です。

YAML 自体には繰り返し機能などがないので、単に下記の様にフォーマット文字列を連結して YAML 文字列を生成しています。もしかしたら、Jinja のようなテンプレートエンジンを使った方が綺麗にかけるかもしれません。

for attr in attr_names:
  s += f"""
  - - Text:
        _: {attr.capitalize()}
        size: [4, 1]
        font: ["Helvetica", 14]
    - Text:
        _: {str(attr_value[attr])}
        size: [7, 1]
        k: attr.{attr}.value
    - Text:
        _: {str(point_need[attr_value[attr]])}
        size: [6, 1]
        k: attr.{attr}.point
    - Button:
        _: "+"
        size: [3, 1]
        k: attr.{attr}.plus
        disabled: false
    - Button:
        _: "-"
        size: [3, 1]
        k: attr.{attr}.minus
        disabled: true
  """

ボタンなどのイベントハンドリングは

    if event.startswith('attr.'):
      es = event.split('.')
      attr, sign = es[1], es[2]
      match sign:
        case "plus":
          if attr_value[attr] < 15:
            attr_value[attr] += 1
        case "minus":
          if attr_value[attr] > 8:
            attr_value[attr] -= 1
        case _:
          print(f"unknown event: {event}")
      for attr in attr_names:
        rules.widgets[f"attr.{attr}.value"].update(value=str(attr_value[attr]))
        rules.widgets[f"attr.{attr}.point"].update(value=str(point_need[attr_value[attr]]))
        rules.widgets[f"attr.{attr}.plus"].update(disabled=(attr_value[attr] == 15))
        rules.widgets[f"attr.{attr}.minus"].update(disabled=(attr_value[attr] == 8))
      total = sum([point_need[attr_value[k]] for k in attr_names])
      rules.widgets['attr.total.point'].update(value=f"{total}/{point_max}")
      rules.widgets['attr.finish'].update(disabled=(not total == point_max))

こんな感じで、メインループのモデルオブジェクト attr_value の値を増減しつつ、値に応じて表示の書き換えやボタンの disable などの処理をしています。
モデルと表示内容の同期や、ボタンの disable 処理などは定型処理と思うので、こっちも YAML に書いて済ませたい気もします。そうすると、簡易インタプリタっぽいものを実装しないとダメかも。

という訳で、何か良い方法は無いか考えてみます。

Discussion