回答編集履歴
7
追記: 2つのイベントループを結合する方法
answer
CHANGED
@@ -95,4 +95,70 @@
|
|
95
95
|
|
96
96
|
注意点: 終了時に tk/qt 側で何か処理を行う場合は、
|
97
97
|
daemon=False にして join メソッドでプロセスの終了を待ちます。
|
98
|
-
その場合、安全に各GUIのイベントループを終了する仕組みが必要になります。
|
98
|
+
その場合、安全に各GUIのイベントループを終了する仕組みが必要になります。
|
99
|
+
|
100
|
+
|
101
|
+
----
|
102
|
+
qt/tk のイベントループを結合する方法
|
103
|
+
|
104
|
+
独自のイベントループを使う為、終了時のイベント処理は未対応。
|
105
|
+
|
106
|
+
デメリット:
|
107
|
+
- Qt の aboutToQuit シグナル等は期待通りに処理されない等、他への影響があります。
|
108
|
+
- 片方の遅延がもう片方に影響する。(tk のイベント処理が遅れると qt も遅くなる → 動作が重く)
|
109
|
+
|
110
|
+
別プロセスにした方が良いと思いますが、2つ以上のイベントループを使いたい場合、
|
111
|
+
このようなアプローチにすることも有ります。(例: asyncio + GUI 等)
|
112
|
+
|
113
|
+
```python
|
114
|
+
import sys
|
115
|
+
import time
|
116
|
+
from functools import partial
|
117
|
+
from types import SimpleNamespace
|
118
|
+
|
119
|
+
import tkinter as tk
|
120
|
+
from PyQt5.QtCore import pyqtSignal
|
121
|
+
from PyQt5.QtWidgets import QApplication, QMainWindow
|
122
|
+
|
123
|
+
def my_quit(app, root, shared):
|
124
|
+
shared.stop_request = True
|
125
|
+
|
126
|
+
def my_event_loop(app, root, shared):
|
127
|
+
while not shared.stop_request:
|
128
|
+
root.update()
|
129
|
+
app.processEvents()
|
130
|
+
time.sleep(0.1)
|
131
|
+
app.quit()
|
132
|
+
root.destroy()
|
133
|
+
|
134
|
+
def main():
|
135
|
+
app = QApplication(sys.argv)
|
136
|
+
root = tk.Tk()
|
137
|
+
shared = SimpleNamespace(
|
138
|
+
stop_request = False,
|
139
|
+
)
|
140
|
+
cleanup = partial(my_quit, app, root, shared)
|
141
|
+
|
142
|
+
# tk widgets
|
143
|
+
root.protocol("WM_DELETE_WINDOW", cleanup)
|
144
|
+
button = tk.Button(root, text="OK")
|
145
|
+
button.pack()
|
146
|
+
|
147
|
+
# qt widgets
|
148
|
+
class MyMainWindow(QMainWindow):
|
149
|
+
closed = pyqtSignal()
|
150
|
+
def closeEvent(self, event):
|
151
|
+
self.closed.emit()
|
152
|
+
event.accept()
|
153
|
+
win = MyMainWindow()
|
154
|
+
win.closed.connect(cleanup)
|
155
|
+
win.show()
|
156
|
+
|
157
|
+
# XXX: app.aboutToQuit does not work
|
158
|
+
|
159
|
+
my_event_loop(app, root, shared)
|
160
|
+
|
161
|
+
|
162
|
+
if __name__ == '__main__':
|
163
|
+
main()
|
164
|
+
```
|
6
説明補足
answer
CHANGED
@@ -27,10 +27,6 @@
|
|
27
27
|
----
|
28
28
|
|
29
29
|
```python
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
30
|
def tk_main(shared):
|
35
31
|
import tkinter as tk
|
36
32
|
from tkinter import ttk
|
@@ -95,4 +91,8 @@
|
|
95
91
|
|
96
92
|
qt <-> tk 間の連携には「プロセス間通信」を調べて見て下さい、
|
97
93
|
qt 側で読み取る Queue や tk 側で読み取る Queue を増やし、
|
98
|
-
Queue を通じてメッセージのやり取りをすることになります。
|
94
|
+
Queue を通じてメッセージのやり取りをすることになります。
|
95
|
+
|
96
|
+
注意点: 終了時に tk/qt 側で何か処理を行う場合は、
|
97
|
+
daemon=False にして join メソッドでプロセスの終了を待ちます。
|
98
|
+
その場合、安全に各GUIのイベントループを終了する仕組みが必要になります。
|
5
コード修正
answer
CHANGED
@@ -28,6 +28,9 @@
|
|
28
28
|
|
29
29
|
```python
|
30
30
|
|
31
|
+
|
32
|
+
|
33
|
+
|
31
34
|
def tk_main(shared):
|
32
35
|
import tkinter as tk
|
33
36
|
from tkinter import ttk
|
@@ -51,14 +54,16 @@
|
|
51
54
|
app = QApplication(shared.argv)
|
52
55
|
win = QMainWindow()
|
53
56
|
button = QPushButton("Quit", win)
|
54
|
-
button.clicked.connect(
|
57
|
+
button.clicked.connect(win.close)
|
55
58
|
win.show()
|
56
59
|
|
60
|
+
app.aboutToQuit.connect(lambda: shared.queue.put(None))
|
57
61
|
app.exec_()
|
58
62
|
|
59
63
|
|
60
64
|
def main():
|
61
65
|
import sys
|
66
|
+
from types import SimpleNamespace
|
62
67
|
from multiprocessing import Process, Queue
|
63
68
|
|
64
69
|
shared = SimpleNamespace(
|
@@ -78,6 +83,7 @@
|
|
78
83
|
if __name__ == '__main__':
|
79
84
|
main()
|
80
85
|
|
86
|
+
|
81
87
|
```
|
82
88
|
|
83
89
|
tkinter と pyqt のウィンドウを同時に開くサンプル
|
4
追記: Process を使う方法
answer
CHANGED
@@ -22,4 +22,71 @@
|
|
22
22
|
```
|
23
23
|
|
24
24
|
同時にイベントループを稼働する方法は、終了時に同期を取る方法が難しい為、
|
25
|
-
別プロセスを検討した方が良さそうです。
|
25
|
+
別プロセスを検討した方が良さそうです。
|
26
|
+
|
27
|
+
----
|
28
|
+
|
29
|
+
```python
|
30
|
+
|
31
|
+
def tk_main(shared):
|
32
|
+
import tkinter as tk
|
33
|
+
from tkinter import ttk
|
34
|
+
from functools import partial
|
35
|
+
|
36
|
+
main_quit = partial(shared.queue.put, None)
|
37
|
+
|
38
|
+
root = tk.Tk()
|
39
|
+
button = ttk.Button(root, text="Quit")
|
40
|
+
button.config(command=main_quit)
|
41
|
+
button.pack()
|
42
|
+
|
43
|
+
root.protocol("WM_DELETE_WINDOW", main_quit)
|
44
|
+
|
45
|
+
root.mainloop()
|
46
|
+
|
47
|
+
|
48
|
+
def qt_main(shared):
|
49
|
+
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
|
50
|
+
|
51
|
+
app = QApplication(shared.argv)
|
52
|
+
win = QMainWindow()
|
53
|
+
button = QPushButton("Quit", win)
|
54
|
+
button.clicked.connect(lambda: shared.queue.put(None))
|
55
|
+
win.show()
|
56
|
+
|
57
|
+
app.exec_()
|
58
|
+
|
59
|
+
|
60
|
+
def main():
|
61
|
+
import sys
|
62
|
+
from multiprocessing import Process, Queue
|
63
|
+
|
64
|
+
shared = SimpleNamespace(
|
65
|
+
argv = sys.argv,
|
66
|
+
queue = Queue(),
|
67
|
+
)
|
68
|
+
procTk = Process(target=tk_main, args=(shared,), daemon=True)
|
69
|
+
procQt = Process(target=qt_main, args=(shared,), daemon=True)
|
70
|
+
|
71
|
+
procTk.start()
|
72
|
+
procQt.start()
|
73
|
+
|
74
|
+
for item in iter(shared.queue.get, None):
|
75
|
+
queue.task_done()
|
76
|
+
|
77
|
+
|
78
|
+
if __name__ == '__main__':
|
79
|
+
main()
|
80
|
+
|
81
|
+
```
|
82
|
+
|
83
|
+
tkinter と pyqt のウィンドウを同時に開くサンプル
|
84
|
+
このコードでは合計3つのプロセスを使いますが、最少は qt と tk の2つでも良いです。
|
85
|
+
終了時の処理を解りやすくするために3つにしました。
|
86
|
+
|
87
|
+
メインのプロセスではキューへのメッセージを待ち、
|
88
|
+
None が入れられるとプログラムを終了します。
|
89
|
+
|
90
|
+
qt <-> tk 間の連携には「プロセス間通信」を調べて見て下さい、
|
91
|
+
qt 側で読み取る Queue や tk 側で読み取る Queue を増やし、
|
92
|
+
Queue を通じてメッセージのやり取りをすることになります。
|
3
文章の修正
answer
CHANGED
@@ -22,4 +22,4 @@
|
|
22
22
|
```
|
23
23
|
|
24
24
|
同時にイベントループを稼働する方法は、終了時に同期を取る方法が難しい為、
|
25
|
-
別プロセス
|
25
|
+
別プロセスを検討した方が良さそうです。
|
2
修正
answer
CHANGED
@@ -17,8 +17,8 @@
|
|
17
17
|
# 双方のイベントループを動かす独自のイベントループを実装する
|
18
18
|
def my_event_loop():
|
19
19
|
while True:
|
20
|
-
print("tk") # update
|
20
|
+
print("tk") # root.update() ... tk のイベント処理
|
21
|
-
print("qt") # processEvents
|
21
|
+
print("qt") # app.processEvents() ... qt のイベント処理
|
22
22
|
```
|
23
23
|
|
24
24
|
同時にイベントループを稼働する方法は、終了時に同期を取る方法が難しい為、
|
1
説明補足
answer
CHANGED
@@ -19,4 +19,7 @@
|
|
19
19
|
while True:
|
20
20
|
print("tk") # update
|
21
21
|
print("qt") # processEvents
|
22
|
-
```
|
22
|
+
```
|
23
|
+
|
24
|
+
同時にイベントループを稼働する方法は、終了時に同期を取る方法が難しい為、
|
25
|
+
別プロセスで使う方を検討した方が良さそうです。
|