見出し画像

tkinterのmainloop代替


Copilotに質問

前回のこれ

割り切って次へ進むつもりが、またどうも気になってしまって、Copilot先生に質問。

tkinter のTkオブジェクトのmainloop()の代替

>tkinter のTkオブジェクトのmainloop()を使う代わりにupdate()を使って同じ動作を記述するとどうなりますか?

updateメソッドは何のため?

>update()を使用して同じ動作を記述することは技術的には可能ですが、一般的には推奨されません。
とのことですが、それではどういうときのためにupdateメソッドが用意されているのでしょうか?

やってみる

mainloop()を使用したコード

tkinter用にCopilotが書いてくれたコード

import tkinter as tk

root = tk.Tk()
label = tk.Label(root, text="Hello, World!")
label.pack()

root.mainloop()

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")
無事動きます

これは、(当然ですが)どちらも正常に動作します。

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()

これでエラー無く動作しますよ。(そりゃそうですよね。)
 それじゃあ意味ないのではないか?あるいは自前の処理をループに統合できるなら価値があるのか?

 なおも「もやもや」は晴れないのであります。

いいなと思ったら応援しよう!