回答編集履歴

8

修正

2020/05/22 12:33

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -196,7 +196,7 @@
196
196
 
197
197
 
198
198
 
199
-
199
+ ### ここは別スレッドで行う ###
200
200
 
201
201
  class Worker(QObject):
202
202
 
@@ -302,6 +302,8 @@
302
302
 
303
303
 
304
304
 
305
+ ### メインスレッド ###
306
+
305
307
  if __name__ == '__main__':
306
308
 
307
309
  app = QApplication(sys.argv)

7

修正

2020/05/22 12:33

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -161,3 +161,183 @@
161
161
  while やすぐに終了しない重たい処理を行ってしまうと、そのイベントループが止まってしまうので、GUI がフリーズしたようになります。
162
162
 
163
163
  なので、while や重たい処理を行いたい場合は別にスレッドを作って行う必要があります。
164
+
165
+
166
+
167
+ ## 追記
168
+
169
+
170
+
171
+ > 「物体を検知してドアを開閉する」処理と「ドアの開閉状態をテキストボックスに入力する」処理をマルチスレッド(threading)で並列処理する『処理Z』をつくればよろしいのでしょうか?
172
+
173
+
174
+
175
+ ドアの開閉を行う処理を別スレッドで行う必要があると思います。
176
+
177
+ 図にすると以下のようになります。
178
+
179
+ ドアが開閉されたら、シグナルを発呼し、メインスレッド側のスロットで受信し、テキストボックスに開閉状態を表示すればよいと思います。
180
+
181
+
182
+
183
+ ![イメージ説明](3de1d9ecfe1b3ae7202ca0c5c78e4c2a.png)
184
+
185
+
186
+
187
+ ```python
188
+
189
+ import sys
190
+
191
+ from datetime import datetime
192
+
193
+ from PyQt5.QtWidgets import *
194
+
195
+ from PyQt5.QtCore import *
196
+
197
+
198
+
199
+
200
+
201
+ class Worker(QObject):
202
+
203
+ doorOpened = pyqtSignal()
204
+
205
+
206
+
207
+ def __init__(self, parent=None):
208
+
209
+ QObject.__init__(self, parent=parent)
210
+
211
+
212
+
213
+ def process(self):
214
+
215
+ while True:
216
+
217
+ QThread.sleep(3)
218
+
219
+ # 実際はドアを開閉する処理などを書く
220
+
221
+
222
+
223
+ # ドアの開閉を通知
224
+
225
+ self.doorOpened.emit()
226
+
227
+
228
+
229
+ class MainWindow(QMainWindow):
230
+
231
+ stop_signal = pyqtSignal()
232
+
233
+
234
+
235
+ def __init__(self):
236
+
237
+ super().__init__()
238
+
239
+ self.initUI()
240
+
241
+
242
+
243
+ def initUI(self):
244
+
245
+ widget = QWidget()
246
+
247
+ self.setFixedSize(640, 480)
248
+
249
+ self.setCentralWidget(widget)
250
+
251
+
252
+
253
+ layout = QVBoxLayout()
254
+
255
+ widget.setLayout(layout)
256
+
257
+
258
+
259
+ # LineEdit を配置する。
260
+
261
+ self.lineEdit = QLineEdit("処理開始")
262
+
263
+ layout.addWidget(self.lineEdit)
264
+
265
+
266
+
267
+ # スレッドを作成する。
268
+
269
+ self.thread = QThread()
270
+
271
+
272
+
273
+ # worker を作成し、メインスレッドから先程作成したスレッドに移す。
274
+
275
+ self.worker = Worker()
276
+
277
+ self.worker.moveToThread(self.thread)
278
+
279
+
280
+
281
+ # signal slot の設定
282
+
283
+ self.thread.started.connect(self.worker.process) # スレッド開始後に process() 開始
284
+
285
+ self.worker.doorOpened.connect(self.func) # doorOpened() が発呼されたら、func() を呼ぶ
286
+
287
+
288
+
289
+ # スレッドを開始
290
+
291
+ self.thread.start()
292
+
293
+
294
+
295
+ def func(self):
296
+
297
+ # ドアの開閉が通知されたら、テキストボックスに表示する
298
+
299
+ now = datetime.now()
300
+
301
+ self.lineEdit.setText(f"Door opened! {now}")
302
+
303
+
304
+
305
+ if __name__ == '__main__':
306
+
307
+ app = QApplication(sys.argv)
308
+
309
+ windows = MainWindow()
310
+
311
+ windows.show()
312
+
313
+ app.exec_()
314
+
315
+ sys.exit(0)
316
+
317
+ ```
318
+
319
+
320
+
321
+ ここで詳解するのは、スペース的に厳しいので、概要と検索キーワードを示しておきます。
322
+
323
+
324
+
325
+ * スレッド間のやり取り: Qt のシグナルスロットを使う
326
+
327
+ → 検索キーワード「Qt シグナルスロット」
328
+
329
+
330
+
331
+ * マルチスレッド: QThread を使う
332
+
333
+ → 検索キーワード「QThread」
334
+
335
+
336
+
337
+ ## 蛇足
338
+
339
+
340
+
341
+ ロボットのシステム開発だと、いくつかの処理を並列で実行しつつ、各処理間でデータをやり取りする必要があるので、システムが複雑になってくると、マルチスレッドのプログラムを書くのは大変になってきます。
342
+
343
+ なので、ROS というロボット用のフレームワーク (ライブラリ) がよく使われます。

6

修正

2020/05/22 12:30

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -118,7 +118,7 @@
118
118
 
119
119
  self.timer = QTimer()
120
120
 
121
- self.timer.timeout.connect(self.on_timeout) # QTimer がストップして timeout シグナルが発呼された場合に呼び出す関数を登録
121
+ self.timer.timeout.connect(self.on_timeout) # QTimer が timeout た場合に呼び出す関数を登録
122
122
 
123
123
  self.timer.start(2000) # タイマーをスタートさせる
124
124
 
@@ -126,7 +126,7 @@
126
126
 
127
127
  def on_timeout(self):
128
128
 
129
- """タイマーがストップしたに呼ぶ関数
129
+ """start() で設定したミリ秒ごとこの処理がばれます
130
130
 
131
131
  """
132
132
 

5

修正

2020/05/21 11:00

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -58,13 +58,13 @@
58
58
 
59
59
 
60
60
 
61
- QTimer の使い方の例を以下に記載します。
61
+ ### サンプルコード
62
-
63
- 「タイマースタート」をクリックすると、2秒後に `on_timeout()` が呼ばれて、lineedit が更新されるサンプルです。
64
62
 
65
63
 
66
64
 
65
+ QTimer の使い方の例を以下に記載します。
66
+
67
- ![ジ説明](7eb4773d03362f35aa6fd48fcd7b30e4.png)
67
+ 「タスタート」をクリックすると、2秒ごとに `on_timeout()` が呼ばれます。
68
68
 
69
69
 
70
70
 
@@ -114,14 +114,6 @@
114
114
 
115
115
 
116
116
 
117
- # ラベルを配置する。
118
-
119
- self.lineEdit = QLineEdit(self)
120
-
121
- layout.addWidget(self.lineEdit)
122
-
123
-
124
-
125
117
  def startTimer(self):
126
118
 
127
119
  self.timer = QTimer()
@@ -129,8 +121,6 @@
129
121
  self.timer.timeout.connect(self.on_timeout) # QTimer がストップして timeout シグナルが発呼された場合に呼び出す関数を登録
130
122
 
131
123
  self.timer.start(2000) # タイマーをスタートさせる
132
-
133
- self.lineEdit.setText('Timer starts')
134
124
 
135
125
 
136
126
 
@@ -140,7 +130,7 @@
140
130
 
141
131
  """
142
132
 
143
- self.lineEdit.setText('Timer stopped')
133
+ print("timeout")
144
134
 
145
135
 
146
136
 

4

修正

2020/05/21 10:57

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -36,7 +36,7 @@
36
36
 
37
37
 
38
38
 
39
- 今のコードは実行すると、X() を呼び出すと、なにも起こらずにただちに終了します。
39
+ 今のコードは X() を呼び出すと、なにも起こらずにただちに終了します。
40
40
 
41
41
  本来やりたい意図は置いておいて、問題点がいくつかあるのでコメント形式で書きました。
42
42
 

3

修正

2020/05/21 10:35

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -25,3 +25,149 @@
25
25
 
26
26
 
27
27
  本来どのようなことが行いたかったのかコメントいただければアドバイスできるかもしれません。
28
+
29
+
30
+
31
+ ## 追記
32
+
33
+
34
+
35
+ > 今のコードでは、「処理Xが実行された0.1秒後に処理Xは止まり、処理Yが実行される」という解釈でよろしかったでしょうか?
36
+
37
+
38
+
39
+ 今のコードは実行すると、X() を呼び出すと、なにも起こらずにただちに終了します。
40
+
41
+ 本来やりたい意図は置いておいて、問題点がいくつかあるのでコメント形式で書きました。
42
+
43
+
44
+
45
+ ```python
46
+
47
+ def X(self):
48
+
49
+ self.Y # 関数呼び出しになっていない self.Y() では?
50
+
51
+ timer=QTimer()
52
+
53
+ timer.timeout.comect(self.Y) # comect() は connect() のスペルミスでは?
54
+
55
+ time.start(100) # start() という関数はタイマーをスタートさせるだけでここで処理はブロックされない。このあと、すぐに関数を抜けて、timer 変数が破棄されてしまうので、ローカル変数ではなく、self.timer のように属性として持っておかないとまずい
56
+
57
+ ```
58
+
59
+
60
+
61
+ QTimer の使い方の例を以下に記載します。
62
+
63
+ 「タイマースタート」をクリックすると、2秒後に `on_timeout()` が呼ばれて、lineedit が更新されるサンプルです。
64
+
65
+
66
+
67
+ ![イメージ説明](7eb4773d03362f35aa6fd48fcd7b30e4.png)
68
+
69
+
70
+
71
+ ```python
72
+
73
+ import sys
74
+
75
+ from PyQt5.QtWidgets import *
76
+
77
+ from PyQt5.QtCore import *
78
+
79
+
80
+
81
+
82
+
83
+ class MainWindow(QMainWindow):
84
+
85
+ def __init__(self):
86
+
87
+ super().__init__()
88
+
89
+ self.initUI()
90
+
91
+
92
+
93
+ def initUI(self):
94
+
95
+ widget = QWidget()
96
+
97
+ self.setCentralWidget(widget)
98
+
99
+
100
+
101
+ layout = QVBoxLayout()
102
+
103
+ widget.setLayout(layout)
104
+
105
+
106
+
107
+ # ボタンを配置する。
108
+
109
+ self.button = QPushButton("タイマースタート")
110
+
111
+ self.button.clicked.connect(self.startTimer)
112
+
113
+ layout.addWidget(self.button)
114
+
115
+
116
+
117
+ # ラベルを配置する。
118
+
119
+ self.lineEdit = QLineEdit(self)
120
+
121
+ layout.addWidget(self.lineEdit)
122
+
123
+
124
+
125
+ def startTimer(self):
126
+
127
+ self.timer = QTimer()
128
+
129
+ self.timer.timeout.connect(self.on_timeout) # QTimer がストップして timeout シグナルが発呼された場合に呼び出す関数を登録
130
+
131
+ self.timer.start(2000) # タイマーをスタートさせる
132
+
133
+ self.lineEdit.setText('Timer starts')
134
+
135
+
136
+
137
+ def on_timeout(self):
138
+
139
+ """タイマーがストップした際に呼ぶ関数
140
+
141
+ """
142
+
143
+ self.lineEdit.setText('Timer stopped')
144
+
145
+
146
+
147
+
148
+
149
+ if __name__ == '__main__':
150
+
151
+ app = QApplication(sys.argv)
152
+
153
+ windows = MainWindow()
154
+
155
+ windows.show()
156
+
157
+ app.exec_()
158
+
159
+ sys.exit(0)
160
+
161
+ ```
162
+
163
+
164
+
165
+ > Whileは処理が重くなるため使ってはいけないのかと感じています。
166
+
167
+
168
+
169
+ GUI アプリケーションは、イベントが発生していないかチェックするイベントループというものがメインスレッドで動いています。
170
+
171
+ while やすぐに終了しない重たい処理を行ってしまうと、そのイベントループが止まってしまうので、GUI がフリーズしたようになります。
172
+
173
+ なので、while や重たい処理を行いたい場合は別にスレッドを作って行う必要があります。

2

2020/05/21 10:26

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -14,9 +14,9 @@
14
14
 
15
15
  QTimer() は名前の通り、ストップウォッチです。
16
16
 
17
- start() に指定したミリ秒分経過すると、タイムアウトの `timeout()` シグナルが呼ばれます。
17
+ start() に指定したミリ秒分経過すると、`timeout()` シグナルが呼ばれます。
18
18
 
19
- `timeout()` シグナルスロットに繋いである場合は、タイムアウトしたときにその関数が呼ばれます。
19
+ `timeout()` シグナルスロットに繋いである場合は、タイムアウトしたときにその関数が呼ばれます。
20
20
 
21
21
 
22
22
 

1

s

2020/05/21 09:50

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -17,3 +17,11 @@
17
17
  start() に指定したミリ秒分経過すると、タイムアウトの `timeout()` シグナルが呼ばれます。
18
18
 
19
19
  `timeout()` シグナルにスロットに繋いである場合は、タイムアウトしたときにその関数が呼ばれます。
20
+
21
+
22
+
23
+ ----
24
+
25
+
26
+
27
+ 本来どのようなことが行いたかったのかコメントいただければアドバイスできるかもしれません。