![見出し画像](https://assets.st-note.com/production/uploads/images/162327987/rectangle_large_type_2_e314566676361848ffaa16e8fd5f5337.jpeg?width=1200)
tkinterのmainloop代替
Copilotに質問
前回のこれ
割り切って次へ進むつもりが、またどうも気になってしまって、Copilot先生に質問。
tkinter のTkオブジェクトのmainloop()の代替
>tkinter のTkオブジェクトのmainloop()を使う代わりにupdate()を使って同じ動作を記述するとどうなりますか?
![](https://assets.st-note.com/img/1731915406-auV0YBHD8xXb2p9rm7sNqi6S.png?width=1200)
![](https://assets.st-note.com/img/1731915461-xUN7eXrk6aEniQdLzZmf139l.png?width=1200)
updateメソッドは何のため?
>update()を使用して同じ動作を記述することは技術的には可能ですが、一般的には推奨されません。
とのことですが、それではどういうときのためにupdateメソッドが用意されているのでしょうか?
![](https://assets.st-note.com/img/1731915679-7V2jSFaiOlnswfhQ1tJu8yHK.png?width=1200)
![](https://assets.st-note.com/img/1731915872-mjt6NiokvK5ThyILweAzGE7F.png?width=1200)
やってみる
mainloop()を使用したコード
tkinter用にCopilotが書いてくれたコード
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Hello, World!")
label.pack()
root.mainloop()
![](https://assets.st-note.com/img/1731916298-8NXz6oSgnQxU7BaHpYcwAZ4T.png)
customtkinter用に、いつものAppクラスで書き換えてみる
import customtkinter as ctk
class App(ctk.CTk):
def __init__(self, title):
super().__init__()
self.title(title)
# widget Label
ctk.CTkLabel(self, text="Hello, World!").pack(padx=100)
self.mainloop()
App("Mainlooptest1")
![](https://assets.st-note.com/img/1731916970-PcDLdQzT9uht50r6ACNUYVsf.png)
これは、(当然ですが)どちらも正常に動作します。
update()を使用したコード
tkinter用
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Hello, World!")
label.pack()
running = True
def on_close():
global running
running = False
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_close)
while running:
root.update_idletasks()
root.update()
正常に動きます。ではこれをcustomtkinter用に書いてみる。
# import tkinter as tk
import customtkinter as ctk
# root = tk.Tk()
root = ctk.CTk()
# label = tk.Label(root, text="Hello, World!")
label = ctk.CTkLabel(root, text="Hello, World!")
label.pack(padx=100)
running = True
def on_close():
global running
running = False
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_close)
while running:
root.update_idletasks()
root.update()
すると、ウインドウを閉じた時に
invalid command name "1747844659008update"
while executing
"1747844659008update"
("after" script)
invalid command name "1747884892608check_dpi_scaling"
while executing
"1747884892608check_dpi_scaling"
("after" script)
というエラーが出てしまいました。(中にある数字は実行のたびに変わります。)
Copilot先生からは、
・ループ処理にsleepを入れる方法
・ループの書き方でafterメソッドを使う方法
を提案されましたが、これらはそれだけでは効果なし。
さらに、afterメソッドを使った上で、末尾にmainloopを付ける次のコードを提案され、
import customtkinter as ctk
root = ctk.CTk()
label = ctk.CTkLabel(root, text="Hello, World!")
label.pack(padx=100)
running = True
def on_close():
global running
running = False
root.destroy()
def update_loop():
if running:
root.update_idletasks()
root.update()
root.after(10, update_loop) # 10ミリ秒後に再帰的に呼び出す
root.protocol("WM_DELETE_WINDOW", on_close)
update_loop() # イベントループを開始
root.mainloop()
やってみるとこれは、正常に動作し、エラー無く終了する。
「おお、すごい」とおもったものの、あれれupdate_loop()をコメントアウトしても、
import customtkinter as ctk
root = ctk.CTk()
label = ctk.CTkLabel(root, text="Hello, World!")
label.pack(padx=100)
running = True
def on_close():
global running
running = False
root.destroy()
def update_loop():
if running:
root.update_idletasks()
root.update()
root.after(10, update_loop) # 10ミリ秒後に再帰的に呼び出す
root.protocol("WM_DELETE_WINDOW", on_close)
# update_loop() # イベントループを開始
root.mainloop()
これでエラー無く動作しますよ。(そりゃそうですよね。)
それじゃあ意味ないのではないか?あるいは自前の処理をループに統合できるなら価値があるのか?
なおも「もやもや」は晴れないのであります。