

10×20の盤を設定してその中をセルがw,d,s,aキー操作で移動できるプログラムを作ろうと思い、以下のコードを作成したところ、1回実行するときは想像通りに動くのですがウインドウを消して、もう一回実行しようとするとキー操作に反応しなくなり「RuntimeError:
main thread is not in main loop」とエラーが出てしまいました。(IDEを再起動するとまた1回だけ正常に動きます。)  
[![表示されるGUI](https://i.stack.imgur.com/GXRtw.png)](https://i.stack.imgur.com/GXRtw.png)

[code]

    import tkinter as tk
    import keyboard
    
    class client_gui:
        
        def __init__(self):
            self.cells = []
    
            root = tk.Tk()
            root.title(u'canvas')
            root.geometry('200x400')
            root.configure(background='blue')
            
            #cell面の構築
            for i in range(20):
                tmp = []
                for j in range(10):
                    tmp.append(tk.Canvas(root, width = 20, height = 20, bg='red', highlightthickness=0))
                    tmp[j].create_rectangle(0, 0, 20, 20, fill = 'white', tag="cell")
                    tmp[j].grid(row=i, column=j, padx=0, pady=0, ipadx=0, ipady=0, sticky=tk.N+tk.E+tk.S+tk.W)  
                self.cells.append(tmp)
            
            #セル色の変更
            self.x=4
            self.y=5
            self.cells[self.x][self.y].itemconfig("cell", fill="black")
            
            keyboard.on_press_key("w", lambda _:self.move(-1, 0))
            keyboard.on_press_key("d", lambda _:self.move(0, 1))
            keyboard.on_press_key("s", lambda _:self.move(1, 0))
            keyboard.on_press_key("a", lambda _:self.move(0, -1))
            
            
            root.mainloop()
            
                
    
        def move(self, dirc_x, dirc_y):
            print(str(dirc_x))
            self.cells[self.x][self.y].itemconfig("cell", fill="white")
            self.x+=dirc_x
            self.y+=dirc_y
            self.cells[self.x][self.y].itemconfig("cell", fill="black")
            
    
    if __name__ == "__main__":
        client_gui()
    
    
[/code]

そこで、ウィンドウクローズイベントが別のスレッドで動いており、ウィンドウを消してもそのスレッドが終了していないことが原因であるのではと考え、client_guiクラスを以下のように書き換えたところ、プログラムを実行したと同時(ウィンドウの×ボタンを押していなくても)にウィンドウクローズを確認する小画面が出てきてしまいました。

[code]

    class client_gui:
        
        def __init__(self):
            self.cells = []
    
            root = tk.Tk()
            root.title(u'canvas')
            root.geometry('200x400')
            root.configure(background='blue')
            
            #cell面の構築
            for i in range(20):
                tmp = []
                for j in range(10):
                    tmp.append(tk.Canvas(root, width = 20, height = 20, bg='red', highlightthickness=0))
                    tmp[j].create_rectangle(0, 0, 20, 20, fill = 'white', tag="cell")
                    tmp[j].grid(row=i, column=j, padx=0, pady=0, ipadx=0, ipady=0, sticky=tk.N+tk.E+tk.S+tk.W)  
                self.cells.append(tmp)
            
            #セル色の変更
            self.x=4
            self.y=5
            self.cells[self.x][self.y].itemconfig("cell", fill="black")
            #cells[2][5].itemconfig("cell", fill="black")
            
            root.protocol("WM_DELETE_WINDOW", self.on_closing(root))
            
            keyboard.on_press_key("r", lambda _:print("r"))
            
            keyboard.on_press_key("w", lambda _:self.move(-1, 0))
            keyboard.on_press_key("d", lambda _:self.move(0, 1))
            keyboard.on_press_key("s", lambda _:self.move(1, 0))
            keyboard.on_press_key("a", lambda _:self.move(0, -1))
            
            
            root.mainloop()
            
            
        def on_closing(self, root):
            if tk.messagebox.askokcancel("Quit", "Do you want to quit?"):
                root.destroy()
                
    
        def move(self, dirc_x, dirc_y):
            print(str(dirc_x))
            self.cells[self.x][self.y].itemconfig("cell", fill="white")
            self.x+=dirc_x
            self.y+=dirc_y
            self.cells[self.x][self.y].itemconfig("cell", fill="black")
    
    
[/code]

WM_DELETE_WINDOWプロトコルはウィンドウクローズボタンが押されたときに実行される処理を紐づけられるという認識で合っているのでしょうか？
また、どのようにしたら正常にプログラムが動くのでしょうか？


CC BY-SA 4.0
2021-06-08T13:19:01.217
77409
2021-06-08T13:19:01.217
46741
question
python tkinter マルチスレッド
TkinterでWM_DELETE_WINDOWを設定したら起動したと同時にクローズドウィンドウが実行されてしまいます。