PythonSimpleGUIでのボタンイベントを発動したい


それぞれに設置してある **「閉じる」ボタン** を押して、  
ウィジェット自身を閉じることができるようにしたい。

メインウィンドウについては、閉じましたので、問題ないです。

①「キーボードを表示、非表示」ボタンを押して、  
keyboardウィジェットを開き、  
**「閉じる」ボタン** を押しても閉じません。

②「テキスト入力ウィンドウを開く」ボタンを押して、  
text_input_windowウィジェットを開き、  
**「閉じる」ボタン** を押しても閉じません。

以上の①、②が分かりません。  
よろしくお願いいたします。

実行したら、エラーメッセージがでませんでした。  
どこから手をつけていいのか分かりません。  
ちなみにコードはIDLEで書いて実行しました。

教えてください。よろしくお願いします。

実行環境:  
Windows 7 (32bit)  
Python 3.8.10  
PySimpleGUI 4.60.4

### 現状のコード

[code]

    import PySimpleGUI as sg
    
    # キーボードクラスの処理
    class Keyboard:
        # 初期処理
        def __init__(self, location=(None, None)):
            
            # レイアウト
            keyboard_layout = [
                                [
                                    sg.Button("閉じる",
                                              key="close",
                                              size=(4, 2)
                                              )
                                    ]
                                ]
            
            # ウィンドウの生成
            self.window = sg.Window(
                                        "keyboard",
                                        keyboard_layout,
                                        keep_on_top=True,
                                        no_titlebar=True,
                                        location=location,
                                        finalize=True
                                    )
    
            # 　アプリ起動時は、キーボードを隠す
            self.hide()
            self.visible = False  # キーボード表示フラグ初期化
    
        # キーボードウィンドウのイベントハンドラ
        def _keyboardhandler(self):
            # イベントの受付
            if self.event is not None:
                # 「閉じる」ボタン押下時の処理
                if self.event == 'close':
                    # キーボードウィンドウを消す
                    self.winsow.hide()                    
    
        # キーボードウィンドウを表示する
        def show(self):
                self.visible = True
                self.window.Reappear()
    
        # キーボードウィンドウを非表示にする
        def hide(self):
                self.visible = False
                self.window.Disappear()
    
        # キーボードウィンドウの表示と非表示を切り替える
        def togglevis(self):
            if self.visible:
                self.hide()
            else:
                self.show()
    
    # テキスト入力ウィンドウクラスの処理
    class TextInputWindow:      
        def __init__(self):
            layout = [
                        [
                            sg.Button(
                                "閉じる",
                                key="text_close",
                                button_color=("black", "white"),
                                enable_events=True,
                            )
                        ]
                    ]
    
            # ウィンドウの生成
            self.window = sg.Window(
                                        "text_input_window",
                                        layout,
                                        size=(400, 300),
                                        finalize=True
                                    )
             
            self.event = None  # イベント初期化
            self.visible = False  # テキストウィンドウ表示フラグ初期化
            
        def show(self):
            self.visible = True
            self.window.Reappear()
    
        def close(self):
            self.visible = False
            self.window.Close()
    
            while True:
                    event, values = self.window.read()
                    if event == sg.WIN_CLOSED or event == 'text_close':
                        self.window.close()
                        break
    
    # GUIクラスの処理
    class GUI:
        def __init__(self):
    
            self.layout = [
                                [
                                    sg.Button(
                                                "キーボードを表示/非表示",
                                                key="keyboard"
                                                ),
                                    sg.Button(
                                                "close",
                                                key="close"
                                                )
                                ],
    
                                [
                                    sg.Text("テキストを入力してください")
                                ],
                                [
                                    sg.Multiline(
                                                    "",
                                                    size=(40, 5),
                                                    key="-TEXT-",
                                                    autoscroll=True,
                                                    enable_events=True
                                                )
                                ],
                                [
                                    sg.Button(
                                            "テキスト入力ウィンドウを開く",
                                            key="open_text_input_window"
                                            )
                                ]
                            ]
    
            self.mainWindow = sg.Window(
                                            "On-screen test",
                                            self.layout,
                                            size=(400, 300),
                                            grab_anywhere=True,
                                            no_titlebar=False,
                                            finalize=True
                                        )
             
            location = self.mainWindow.current_location()
            location = location[0] - 200, location[1] + 200
            #self.keyboard = keyboard(location)
            
            self.event = None  # event変数を初期化
            self.keyboard_visible = False  # キーボードの表示状態を管理する変数を追加
    
            self.text_input_window = None
            self.keyboard = Keyboard()
    
        def run(self):
            event, values = self.mainWindow.read(timeout=200, timeout_key='timeout')
            while True:
                # イベントを取得
                event, values = self.mainWindow.read(timeout=200, timeout_key='timeout')
                if event == 'open_text_input_window':
                    if self.text_input_window is None:
                        self.text_input_window = TextInputWindow()
              
                elif event == 'keyboard':
                    self.keyboard.togglevis()
    
                if event == "close" or event == sg.WIN_CLOSED:
                    # ユーザーが×ボタンを押した場合
                    if event == sg.WIN_CLOSED:
                        self.mainWindow.close()
                        break
                    else:
                        confirm = sg.popup_yes_no("終了しますか？", title="確認", keep_on_top=True)
                        if confirm == "Yes":
                            self.mainWindow.close()
                            break
    
            # 　各種ウィンドウをクローズ
            self.keyboard.hide()
            if self.text_input_window:
                self.text_input_window.close()
             
    if __name__ == "__main__":
        app = GUI()
        app.run()
    
[/code]




`run`関数の`while True:`ブロック内でループしウィジェットの入力を取得していると思います  
そこで`self.mainWindow.read`だけではメインウィンドウのウィジェットしか取得できません  
なので別ウィンドウのボタンには無反応となっているようです  
`while True:`ブロックに以下のコードを追加すると`text_input_window`の入力を取得できそうです

[code]

    if self.text_input_window is not None:
        event_1, values_1 = self.text_input_window.window.read(
            timeout=200, timeout_key="timeout"
        )
    
[/code]

具体的な処理は書いてないのでご自身で追加してください  
私は初心者なので思いつきの解答です。もっと良い方法があるかもしれないです。

追記  
以下のコードに置き換えることで`text_input_window`の表示、非表示は可能です  
(`run`関数の宣言から`elif event == 'keyboard':`の手前までです)

[code]

    def run(self):
        event, values = self.mainWindow.read(timeout=200, timeout_key="timeout")
        while True:
            # イベントを取得
            event, values = self.mainWindow.read(timeout=200, timeout_key="timeout")
    
            # text_input_window イベント取得
            if self.text_input_window is not None:
                event_1, values_1 = self.text_input_window.window.read(
                    timeout=200, timeout_key="timeout"
                )
                #text_input_window 閉じる押されたら隠す
                if event_1 == "text_close":
                    self.text_input_window.window.hide()
    
            if event == "open_text_input_window":
                if self.text_input_window is None:
                    self.text_input_window = TextInputWindow()
                else:
                    #text_input_window 再表示
                    self.text_input_window.window.un_hide()
    
[/code]




`run`関数の`while True:`ブロック内でループしウィジェットの入力を取得していると思います  
そこで`self.mainWindow.read`だけではメインウィンドウのウィジェットしか取得できません  
なので別ウィンドウのボタンには無反応となっているようです  
`while True:`ブロックに以下のコードを追加すると`text_input_window`の入力を取得できそうです

[code]

    if self.text_input_window is not None:
        event_1, values_1 = self.text_input_window.window.read(
            timeout=200, timeout_key="timeout"
        )
    
[/code]

具体的な処理は書いてないのでご自身で追加してください  
私は初心者なので思いつきの解答です。もっと良い方法があるかもしれないです。

追記  
以下のコードに置き換えることで`text_input_window`の表示、非表示は可能です  
(`run`関数の宣言から`elif event == 'keyboard':`の手前までです)

[code]

    def run(self):
        event, values = self.mainWindow.read(timeout=200, timeout_key="timeout")
        while True:
            # イベントを取得
            event, values = self.mainWindow.read(timeout=200, timeout_key="timeout")
    
            # text_input_window イベント取得
            if self.text_input_window is not None:
                event_1, values_1 = self.text_input_window.window.read(
                    timeout=200, timeout_key="timeout"
                )
                #text_input_window 閉じる押されたら隠す
                if event_1 == "text_close":
                    self.text_input_window.window.hide()
    
            if event == "open_text_input_window":
                if self.text_input_window is None:
                    self.text_input_window = TextInputWindow()
                else:
                    #text_input_window 再表示
                    self.text_input_window.window.un_hide()
    
[/code]

