Tkinterで画面表示、別スレッドでウィジェットのステータスを変更します。
スレッドを生成、複数のウィジェットのステータスを変更します。
そこで、ウィンドウの閉じるボタンを押すと応答なしになります。
処理が多すぎるのが原因でしょうか?
time.sleep()の値を増やしたら少しは軽くなりましたが、
この値はあまり増やしたくはありません。
(スレッドをもっと生成して、処理を分散させるべき?)
対処方法はありますか?
Windowsです。
Python
1import threading 2import time 3import tkinter as tk 4 5 6def func(): 7 global flag, labels 8 cnt = 0 9 while flag: 10 for i in range(150): 11 labels[i]["text"] = str(cnt) 12 cnt += 1 13 time.sleep(0.1) 14 15def close(): 16 global flag, thread, win 17 flag = False 18 thread.join() 19 win.destroy() 20 21 22win = tk.Tk() 23win.geometry("200x100") 24 25labels = [] 26for i in range(15): 27 for j in range(10): 28 label = tk.Label(win) 29 label.grid(row=i, column=j) 30 labels.append(label) 31 32flag = True 33thread = threading.Thread(target=func) 34thread.start() 35 36win.protocol("WM_DELETE_WINDOW", close) 37win.mainloop()
thread.join()を消すと応答なしにはなりませんが、
ウィンドウを閉じた後にスレッドの処理をしようとしてエラーになったり、
VSCodeで終わっていないような振る舞い(添付画像)をします。
after()をサブスレッドから呼び出し(これもダメか・・・)
Python
1import tkinter as tk 2import threading 3import queue 4 5def func1(): 6 global flag, labels, win 7 cnt = 0 8 while flag: 9 txt = str(cnt) 10 win.after_idle(lambda:func2(txt)) 11 cnt += 1 12 13def func2(txt): 14 global labels 15 for i in range(150): 16 labels[i]["text"] = txt 17 18def close(): 19 global flag, thread, win 20 flag = False 21 thread.join() 22 win.destroy() 23 24if __name__ == "__main__": 25 26 win = tk.Tk() 27 28 row = 15 29 column = 10 30 labels = [] 31 32 for i in range(row): 33 for j in range(column): 34 label = tk.Label(win) 35 label.grid(row=i, column=j) 36 labels.append(label) 37 38 flag = True 39 thread = threading.Thread(target=func1) 40 thread.start() 41 42 win.protocol("WM_DELETE_WINDOW", close) 43 win.mainloop()
afterの呼び出しをサブスレッドからメインスレッドに変更
(これは上手くいっている?)
Python
1import tkinter as tk 2import threading 3import time 4import queue 5 6def loop(): 7 global data, flag 8 cnt = 0 9 while flag: 10 data.put(str(cnt)) 11 cnt += 1 12 time.sleep(0.1) 13 14def disp(): 15 global data, flag, label1, label2 16 while not data.empty(): 17 tmp = data.get() 18 label1["text"] = tmp 19 label2["text"] = tmp 20 win.after(10, disp) # 指定時間[ms]はloop()の更新時間[s]より短くしないと、while not data.empty()で瞬間的に処理されてしまう 21 22def close(): 23 global flag, thread, win 24 flag = False 25 thread.join() 26 win.destroy() 27 28 29win = tk.Tk() 30 31data = queue.Queue() 32 33label1 = tk.Label(win) 34label1.grid() 35label2 = tk.Label(win) 36label2.grid() 37 38flag = True 39thread = threading.Thread(target=loop) 40thread.start() 41 42# winが存在する(破棄されていない)場合はdisp()を実行 43win.after_idle(disp) # labelを破棄する予定はないので、winでafter設定 44 45win.protocol("WM_DELETE_WINDOW", close) 46win.mainloop()
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/10/23 04:26
2020/10/23 04:39
2020/10/23 06:07 編集