非同期処理と GUI (P)
こちら にしたがって、PySimpleGUI を用いて GUI プログラムを書いている場合についてです。
定期的な処理
アニメーションなど、定期的に実行したい処理がある場合、window.read()
に `timeout`` option をつければ大丈夫です。
これで、GUI イベントが来なくても、指定時間が来たらイベントとして認識してくれます。
後は、定期的に実行したい処理を、対応 event として記述するだけ。
while True:
# 定期的に処理したいことがある場合は、timeout を指定するので十分
event, values = self.window.read(timeout=1000, timeout_key='timeout')
if event == sg.WIN_CLOSED:
break
print(f"event='{event}', code={ord(event[0])}, values={values}\n")
if event == 'timeout':
self.my_time.update(str(datetime.datetime.now()))
asyncio とGUI の協調
まだ詳しくは分かっていないところもあるのですが、多分、以下のような形で組んで大丈夫じゃないかと。
-
このプログラムは、webserver_test/test_server2.pyで起動される(偽)Web API にアクセスするプログラムとなっています。先に、
test_server2.py
を実行した状態で、simpleA_coroutine.py
を実行させてください。 -
GUI のハンドラの中では、await は実行せず、web API 呼び出しも
create_task
してadd_done_callback
を指定するだけにする。- これで、ハンドラの中で長時間停止することはない
- 以下はclick のハンドラの例
def listbox_click(self, value): # 学生クリック時の動作
if len(value) == 0: # value はクリック要素が list として渡される
return
task0 = asyncio.create_task(self.score_service.get_scores(value[0]))
task0.add_done_callback(callback_scores)
print('Click performed.', value)
- 一方で、定期的に co-routine にスケジュールの機会を与えないといけないので、Eventチェックの前に asyncio 処理を入れる
while True:
await asyncio.sleep(0.01) # 他の co-routines にスケジュール機会を与えるため
# GUI Event は、timeout を設定。しないと、GUI event 来るまで「止まり」、
# co-routine を見てくれなくなる
event, values = self.window.read(timeout=200, timeout_key='timeout')
if event == sg.WIN_CLOSED:
break
if event == 'timeout':
continue
if ...
- この例では、window が閉じたら、async タスクがすべて終了したか確認せずに終了することになりますが、それはそれでいいかと。