こちらの続きです。
FletでReactチュートリアルを真似る3 - C#ATIA
hatenaがメンテナンスになっていたので投げていなかったのですが、もう何度も
作り直してます・・・。
悩みに悩んだ末、こちらの素晴らしいStateクラスをお借りしました。
Python(Flet)でリアクティブなUIを作る方法を考える - Qiita
typingの記載方法はバージョンによって異なるのですが、python3.9では
あの書き方で大丈夫なようです。(あまり自信が無い)
お借りしたStateクラスのインスタンスは_squaresとして、Squareクラスはこの様に
修正しました。
#python import flet as ft from copy import deepcopy from state import State _squares = State([None] * 9) class Square(ft.UserControl): def __init__(self, idx): super().__init__(self) self.idx = idx self.square = ft.ElevatedButton( '', width = 30, height = 30, bgcolor = ft.colors.BLUE_100, style = ft.ButtonStyle( shape=ft.RoundedRectangleBorder(radius=0), padding = 1, ), on_click = self.on_click_handler ) _squares.bind(self.on_change_handler) def build(self): return self.square def on_click_handler(self, e): squares = deepcopy(_squares.get()) squares[self.idx] = 'X' _squares.set(squares) def on_change_handler(self): txt = _squares.get()[self.idx] if txt in [self.square.text, None]: return self.square.text = txt self.update()
Stateのインスタンス(_squares)が監視するべきものは、ボタンの状態を表す
9個の配列です。中身はチュートリアル同様の
None, True, False
の何れかで、最初の段階では未クリック状態を示す"None"で初期化しています。
続いて、Squareクラスです。
コンストラクタ(__init__)では、どのボタンか分からなくなってしまうので、
インデックスを受け取る事にしました。
on_clickイベントでon_click_handlerを呼び出しますが、ボタンの文字を変更せず
Stateのインスタンスに現在の様態を投げ込みます。
チュートリアル同様、一度deepcopyしています。実はスライスはディープコピー
だと思ってました・・・。
Stateのインスタンスbindは、監視させたものに変化が有った際に実行されるメソッド
なので、on_change_handlerを割り当てました。
on_change_handlerメソッドではクリックされたボタンの文字を変更しています。
実はこの部分がこれで良いものかどうかが分かっていないのですが、ボタンをクリック
した際に変化されるものは9個の配列に対して、1個です。(2個のボタンを同時には押せない)
しかしon_change_handlerメソッドの呼び出しは9回です。
可能であれば、変化のあったボタンのみの呼び出しとしたいのですが、何処をどの様に
すれば良いのか分かりませんでした。(その為、文字の変更のみは1個にしました)
あぁ1個のボタンに対して、1個のStateのインスタンス作らなきゃいけないのかな?
”ボタン” では無くて ”監視されるもの” に付き1個のStateだろうな。
あぁ見た目や動作は前回と変化ありません。
チュートリアルの意味合いに近い形になった・・・と信じたい。