tkinterで、for文を使用して、canvasを常時変更しているため、常時更新している状況です。
しかし、tkinterを触ったり、他の作業をすると、tkinterが応答なしとなります。処理終了後にはcanvasは更新されますが、応答なしをなくしたく、やはり別処理で実行することを考えております。
ネットで見ると、別処理threadでヒットしますが、分かりにくく、かなり構築しましたので、大きく変更はしたくないです。
そこで、分かりやすく、threadにてtkinterの応答なしをなくす構文を教えていただけないでしょうか?
def ボタンクリック()
for文
ある処理
canvas色変え
ボタン
main.loop
上記の構文ですが、簡単な構文が見当たりません。
ボタンを押すと、tkinterの処理を終了させ、for文で、ある処理と同時にcanvasを色変えしたく思います。
宜しくお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ベストアンサー
「応答なし」になるコード例
python
1#!/usr/bin/env python3.8 2 3import tkinter as tk 4 5if __name__ == '__main__': 6 root = tk.Tk() 7 label = tk.Label(root) 8 label.pack() 9 button = tk.Button(root, text="click") 10 11 def click(): 12 for num in range(100*100): 13 label.config(text=str(num)) 14 # root.update() 15 label.config(text="DONE") 16 17 button.config(command=click) 18 button.pack() 19 root.mainloop()
この場合では、応急処置的に root.update()
を呼び出す事で解消できます。
但し、処理内容に時間が掛かる場合は、定期的にイベントループの処理が呼び出されないと、
やはり応答なしになってしまいます。
スレッドの利用例
python
1#!/usr/bin/env python3.8 2 3import tkinter as tk 4from threading import Thread 5import logging 6 7if __name__ == '__main__': 8 # 関数がどのスレッド実行されているかを確認する 9 logging.basicConfig( 10 level=logging.DEBUG, 11 format="[%(threadName)-10s] %(message)s", 12 ) 13 14 root = tk.Tk() 15 label = tk.Label(root) 16 label.pack() 17 button = tk.Button(root, text="click") 18 19 def set_label(text): 20 # メインスレッドで実行 21 logging.debug("set_label: %s", text) 22 label.config(text=text) 23 24 def worker(root): 25 # ループはスレッドで実行される 26 logging.info("worker start") 27 for num in range(100*100): 28 root.after_idle(set_label, str(num)) 29 root.after_idle(set_label, str(num)) 30 31 def click(): 32 thread = Thread(target=worker, args=(root,), daemon=True) 33 thread.start() 34 35 button.config(command=click) 36 button.pack() 37 root.mainloop()
メインスレッド上でGUIは動き続けるので応答なしにはなりません。
注意点は、別スレッドからは直接 GUI の操作を行ってはいけない点に注意。
問題なく動く場合もありますが、誤動作の原因になります。
python
1 def worker(root): 2 # XXX: スレッドで実行される関数内では、直接GUIを操作しない事 3 # 通常のtkinterでは NG 4 label.config(text="...")
スレッドから直接GUIを操作するようなコードを書きたい場合は、
mtTkinter 等の、スレッドセーフな操作に内部で対応してくれるライブラリがあります。
上記のようなコードを内部でスレッド間のメッセージをやりとりして、メインスレッド上で実行します。
別スレッドからtkinterを操作する対応方法:
root.after_idle に関数を渡す事で、メインスレッドのイベントループから呼び出す事が出来ます。
python
1 def worker(root): 2 root.after_idle(lambda: label.config(text="..."))
投稿2020/12/11 12:23
総合スコア8731
0
他の作業もする場合、root.updateは、tkinterが最上にきませんか?
投稿2020/12/10 11:19
総合スコア168
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/12/11 13:21
2020/12/11 15:20
2020/12/11 15:32 編集
0
簡単な方法は前回の質問で回答した通り、
定期的に update() を呼ぶ事で解消します。描画のみ更新で良い場合は update_idletasks()
python
1def ボタンクリック(): 2 for文 3 ある処理 4 root.update() # tkinterのイベント処理をする
ただし「ある処理」に時間が掛かる場合は、その間応答なしになります。
大きく変更はしたくないです。
残念ながら両立は出来ません。
スレッドを使う以上は、プログラム全体をスレッドセーフな設計にする必要があります。
- 「ある処理のループ」は別スレッドで実行
- 色変え等、GUI描画の処理はメインスレッド側で行う
投稿2020/12/10 11:03
総合スコア8731
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/12/10 11:18
2020/12/10 11:44
2020/12/11 18:42
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/12/11 15:32