回答編集履歴
3
改善例を追記
test
CHANGED
@@ -53,6 +53,68 @@
|
|
53
53
|
- root.title の部分を print に変更すると、GUIへのアクセスは発生しない為、エラーは起こりません。
|
54
54
|
|
55
55
|
- daemon スレッドにする場合も同様ですが、タイミング次第では起こる可能性は残ります(意図的な再現は難しい)
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
上で提示したコードの改善例
|
60
|
+
|
61
|
+
```python
|
62
|
+
|
63
|
+
from threading import Thread, Event
|
64
|
+
|
65
|
+
import tkinter as tk
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
def worker(root, event):
|
70
|
+
|
71
|
+
for num, _ in enumerate(range(5), start=1):
|
72
|
+
|
73
|
+
print(num)
|
74
|
+
|
75
|
+
if event.is_set():
|
76
|
+
|
77
|
+
break
|
78
|
+
|
79
|
+
root.title(f"{num}")
|
80
|
+
|
81
|
+
# NOTE: time.sleep では、メインスレッドで thread.join 時に GUIがフリーズする為、
|
82
|
+
|
83
|
+
# 中断可能な Event.wait を利用。
|
84
|
+
|
85
|
+
event.wait(1)
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
root = tk.Tk()
|
90
|
+
|
91
|
+
event = Event()
|
92
|
+
|
93
|
+
event.clear()
|
94
|
+
|
95
|
+
thread = Thread(target=worker, args=(root, event))
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
def on_close():
|
100
|
+
|
101
|
+
event.set() # 修了を通知
|
102
|
+
|
103
|
+
thread.join() # workerの完了を待つ
|
104
|
+
|
105
|
+
root.destroy() # GUIの破棄 (ウィンドウを閉じる)
|
106
|
+
|
107
|
+
root.protocol("WM_DELETE_WINDOW", on_close)
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
root.after(1000*1, thread.start)
|
112
|
+
|
113
|
+
root.after(1000*3, on_close)
|
114
|
+
|
115
|
+
root.mainloop()
|
116
|
+
|
117
|
+
```
|
56
118
|
|
57
119
|
|
58
120
|
|
2
問題点の追記
test
CHANGED
@@ -1,4 +1,66 @@
|
|
1
|
+
問題点: サブスレッドからのGUIの直接操作
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
メインスレッド終了後(GUIが破棄された後) に、サブスレッドがGUIにアクセスする事になる為、
|
6
|
+
|
7
|
+
問題が起こります。
|
8
|
+
|
1
|
-
デーモンスレッド
|
9
|
+
デーモンスレッドの場合(その他の子スレッドがない場合)、サブスレッドも終了される為
|
10
|
+
|
11
|
+
問題が発生しません。
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
意図的に同じ問題を起こすコード
|
16
|
+
|
17
|
+
```python
|
18
|
+
|
19
|
+
from threading import Thread
|
20
|
+
|
21
|
+
import tkinter as tk
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
def worker(root):
|
26
|
+
|
27
|
+
import time
|
28
|
+
|
29
|
+
for num in range(5):
|
30
|
+
|
31
|
+
root.title(f"{num}")
|
32
|
+
|
33
|
+
time.sleep(1)
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
root = tk.Tk()
|
38
|
+
|
39
|
+
thread = Thread(target=worker, args=(root,))
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
root.after(1000*1, thread.start) # 1秒後に開始
|
44
|
+
|
45
|
+
root.after(1000*3, root.quit) # 3秒後にGUIを終了
|
46
|
+
|
47
|
+
root.mainloop()
|
48
|
+
|
49
|
+
```
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
- root.title の部分を print に変更すると、GUIへのアクセスは発生しない為、エラーは起こりません。
|
54
|
+
|
55
|
+
- daemon スレッドにする場合も同様ですが、タイミング次第では起こる可能性は残ります(意図的な再現は難しい)
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
----
|
62
|
+
|
63
|
+
暫定的な回避策
|
2
64
|
|
3
65
|
|
4
66
|
|
1
書式の修正
test
CHANGED
@@ -1,13 +1,3 @@
|
|
1
|
-
問題個所は特定されいて、
|
2
|
-
|
3
|
-
デーモンスレッドにするという回避策も見出されているようなので、
|
4
|
-
|
5
|
-
その他の方法の
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
----
|
10
|
-
|
11
1
|
デーモンスレッドを使わない場合の、暫定的な回避策
|
12
2
|
|
13
3
|
|