1. きっかけ
シリアル通信をするGUIアプリを作っていました。
すると、応答を待っている間のコンマ数秒アプリがフリーズすることに気付きました。
微妙な差ですがストレスに感じたので解決策を講じました。
2. 結論
-
QUIT
ボタンを作り、そのボタンで呼ばれる関数内でスレッドを終了させる - 無限ループはフラグが立ったら抜け出すようにしておく
- アプリをバツボタンで閉じられるとスレッドが無限ループから抜出せず強制終了するしかなくなるので、バツボタンで閉じられないように設定
3. 実装
- サンプルアプリ
class App(tk.Frame):
def __init__(self, master):
super().__init__(master)
# ウィジェット作成
self.number = tk.IntVar(value=0)
self.label_number = tk.Label(master, textvariable=self.number)
self.button_quit = tk.Button(master, text='QUIT', command=self.quit)
self.label_number.pack()
self.button_quit.pack()
# スレッド
self.quit_flag = False
self.thread = threading.Thread(target=self.infinite_func)
self.thread.start()
- 無限ループの関数
def infinite_func(self):
while not self.quit_flag:
# 数を1ずつ増やす
self.number.set(self.number.get() + 1)
time.sleep(1)
- 終了処理
def quit(self):
# フラグを立てる
self.quit_flag = True
# スレッドの終了を待つ(ウィンドウを閉じる前に!)
self.thread.join()
# ウィンドウを閉じる
self.master.destroy()
- main
def main():
root = tk.Tk()
root.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) # QUITボタン以外の終了操作を許可しない
app = App(master=root)
app.mainloop()
if __name__ == '__main__':
main()
4. 終わりに
コードはGitHubに挙げておきます。
https://github.com/PlusF/TkinterThreadingSample