python_custom_tkinter_あるスレッドでの処理をメインスレッドに反映させる


pythonにおけるスレッド内コンストラクタから登録する

Javaでいう Runnableのメソッドのような関数について、

以下のようなコードを教わりましたが、



def worker2(self):

print("Thread started")


try:

            

# Wait for 10 seconds or until the stop event is set

for i in range(10):


if self.stop_event.is_set():

print("Thread interrupted before completion")

return


# ミリ秒にできないか

time.sleep(1)



print("10 seconds passed")

            

#指定した時間が経過する間テキストボックスへの変更がないので

#入力値が確定するタイミングだろうか

            

# runOnUiThreadのような処理で Entry2に文字列の値を表示

            

except Exception as e:

print(f"Thread encountered an exception: {e}")




上記のコードのうちで、


time.sleep(1)だと1秒間の待機になりますが、


これをミリ秒単位で指定する方法を教えていただきたいのと、



このメソッド内での forループが終了したときに


androidでの

runOnUIのような感じで、UIスレッドで


ui要素の表示の変更


仮に

self.entry2

 = ctk.CTkEntry( self, text="value is not set") 


の表示内容を



"new value"

のような感じに変更したいのですが・・・






Pythonのスレッド内でミリ秒単位で待機するためには、

`time.sleep()`の代わりに`time.sleep()`の引数として

ミリ秒を秒に変換した値を渡す方法があります。


例えば、100ミリ秒の待機を実現したい場合は、

次のように記述します。


```python


time.sleep(0.1)  # 100ミリ秒


```


次に、`worker2`メソッド内でUIスレッドに変更を加えたい場合、

Pythonの`tkinter`でUIを更新するには、

スレッドから直接UIを操作することができません。


`tkinter`では、UI更新はメインスレッドで行う必要があります。

`ctk`(CustomTkinter)を使用している場合も同様です。


スレッドからUIを更新するためには、

スレッド内でイベントをキューに追加し、

UIスレッドでそのイベントを処理する方法を取ります。


以下のように`after()`メソッドを使って、

UIスレッドで実行される関数を指定する方法があります。



```python


import time

import threading

import customtkinter as ctk


class App(ctk.CTk):


def __init__(self):

super().__init__()

self.entry2

= ctk.CTkEntry(self, text="value is not set")

self.entry2.pack(padx=20, pady=20)


self.stop_event = threading.Event()



def worker2(self):

print("Thread started")


try:

for i in range(10):

if self.stop_event.is_set():

print("Thread interrupted before completion")

return

# 100ミリ秒待機

time.sleep(0.1)  


print("10 seconds passed")


# UIスレッドでUI要素の変更

self.after(0, self.update_entry)


except Exception as e:

print(f"Thread encountered an exception: {e}")


def update_entry(self):

self.entry2.configure(text="new value")


def start_thread(self):

thread = threading.Thread(target=self.worker2)

thread.start()


if __name__ == "__main__":


    app = App()

    app.start_thread()

    app.mainloop()

```


このコードでは、

`worker2`メソッド内でスレッドが完了した後、

`after()`メソッドを使ってUIスレッドで`update_entry`メソッドを呼び出し、

`entry2`のテキストを更新しています。


`after()`はUIスレッドで実行されるコールバックをスケジュールするため、

UIの更新がスレッドと競合しないようにします。


ミリ秒単位の待機も含め、スレッド内での処理後にUIの更新が可能です。


コメント