PySimpleGUIの基本的な使いかたが、今一つ把握できていないように思います。
以下、今回の説明に特化してざっくり説明します。
前にも書きましたが、GUIのプログラムでは、プログラム実行中はすべてイベントをきっかけとしてすべてのことが動作します。 イベントというのは、ボタンを押したり、キーボードのキーを押したりすることなどです。
PySimpleGUIでは、whileで作った無限ループの中で、Window.read()を呼ぶことで発生したイベントを取得することができます。 このプログラムでは、 sg.Windowのインスタンスはwinになっています。
python
1while True:
2 event, values = win.read()
このとき、 eventには、ウィジェット(Buttonなど)の定義で keyにしていしたものが入ってきます。なので、ボタンが押されたときには、"だれが'とかではなく**'btn0'**などが入ってきます。なので、質問のif文は間違えています。 また、 if文はいずれかになるので、elifにしたほうがわかりやすいでしょう。
一部書き換えるとこうなりますが、
python
1 if event == 'btn0':
2 random.choice(who) + random.choice(Conjunction)
3 elif event == 'btn1':
4 random.choice(Where)
5 elif event == 'btn2':
6 random.choice(do)
さて、if文の中で、文をランダムに選んでいますが、これでは選んでいるだけで、何も起きません。
random.choice(Where) としても、Whereの中から1つ選ばれますが、どこにも保存されずに捨てられてしまうのです。
以下のexecute関数でそれを使おうとしているのかもしれませんが、その関数はどこからも呼ばれませんし、また、中で参照しているvaluesもwhileループの中でのみ意味のある値を持つ変数なので、ここで使うのは適切ではありません。
python
1def execute():
2 txt = values["btn0"] + values["btn1"] + values["btn2"]
3 win["txt"].update(txt)
直すとしたらこんな感じでしょうか。
- 表示するwho, when, do の値を持つ変数を用意しておく。
- ボタンが押されたときは、その値を変更する。
としましょう。 こうすることで、ボタンを押したときに選んだ値を保持できます。
あとは、textエリアに文章を追加する必要がありますね。 いずれかのボタンが押されて文字が変更になったときに実行すればいいので、
- execute()を変数を使うように変更する。
- 各ボタンの処理の後でexecuteを呼ぶ
ということにします。
これで修正するとこんな感じです。
python
1import PySimpleGUI as sg
2import random
3sg.theme("Darkbrown3")
4
5layout = [[sg.Text(key="txt")],
6 [sg.Button("だれが",key="btn0"),
7 sg.Button("どこで",key="btn1"),
8 sg.Button("何をした",key="btn2")]]
9win = sg.Window("だれがどこで何をしたゲーム",layout,font=(None,14))
10
11who = ["A","B","C"]
12conjunction= ["が"]
13where= ["○○で","□□で","△△で"]
14do =["☓☓した","**した","--した"]
15
16who_str = "WHO"
17where_str = "WHERE"
18do_str = "DO"
19
20def execute():
21 txt = f'{who_str} {where_str} {do_str}'
22 win['txt'].update(txt)
23
24while True:
25 event,values= win.read()
26 if event == 'btn0':
27 who_str = random.choice(who) + random.choice(conjunction)
28 execute()
29 elif event == 'btn1':
30 where_str = random.choice(where)
31 execute()
32 elif event == 'btn2':
33 do_str = random.choice(do)
34 execute()
35 elif event == sg.WIN_CLOSED:
36 break
おまけ
前にtkinterで作っていたものを、PySimpleGUIで作りなおすことにしたのかはわかりませんが、少し簡単になっているとは言っても、GUIのプログラムの動作の基本というのは変りません。イベントはすべてループの中で処理しなければなりませんし、ループの外の処理は、ループの前後でしか実行されません。
また、質問のexecute関数関数のように、関数は明示的に呼ぶようにしなければ勝手に使われることは(通常は)ありません。
おまけ その2
作ったプログラムが動かないとき、何をしていますか?
たとえば、質問のコードでは、ボタンを押しても何も起きませんでしたが、何をしていますか?
そういう問題(バグ)の原因をみつけて取り除くことをデバッグと言います。 デバッグの原始的なものの1つにprintデバッグと呼ばれる手法があります。
"だれが"を押したときに、if文の"だれが" のところに入るはずですよね。 その動作がおかしいのであれば、そのif文の中にprint("だれがに入った!")などを追加して動かしてみるのです。 ボタンを押してそれが表示されれば、その動作はOKで、じゃあ、問題はその中にあるから... というように処理を追い掛けていくことができるのです。
質問のコードはまずは、このif文の中に入りません。 ということは、判定が間違えている、じゃあ、eventには何が入っているかprint()してみよう.. といったことをすれば、 eventには "だれが"ではなく、'btn0'などが入っていることがわかるでしょう。
地道な作業ですが、こういうことを積み重ねることで、だんだんプログラミングのスキルは上っていくものです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/04/05 22:57