質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

14389閲覧

QTimerの使い方を教えてください

pythonnoob1

総合スコア18

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2020/05/21 03:48

前提・実現したいこと

素人質問で大変申し訳ありません。
raspberrypi3b と pyqt5 を使ってロボットを動かすためのGUIを作っています。
そこで、処理Xと処理Yを繰り返しで実行するプログラムを作りたいと思っています。

該当のソースコード

python import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * import subprocess import time import numpy as np import cv2 import RPi.GPIO as GPIO class Tab1Widget(QWidget): def __init__(self): super().__init__() self.title = "GUI test" self.left = 10 self.top = 10 self.width = 640 self.height = 480 self.initUI() self.counter = 0 def initUI(self): super(Tab1Widget, self).__init__() btn1 = QPushButton("停止", self) btn2 = QPushButton("スタート", self) btn1.clicked.connect(self.stop) btn2.clicked.connect(self.X) layoutA = QGridLayout() layoutA.addWidget(btn1,0,0) layoutA.addWidget(btn2,0,1) self.setLayout(layoutA) self.show() def X(self): "処理したいプログラム" self.Y timer=QTimer() timer.timeout.comect(self.Y) time.start(100) def Y(self): "処理したいプログラム" if __name__ == "__main__": app = QApplication(sys.argv) ex = Tab1Widget() sys.exit(app.exec_())

教えてほしいこと

上のプログラムでで「スタートボタン」を押すと処理Xが実行されると思います。
これで、処理Xと処理Yが0.1秒間隔で交互に実行されている認識でいます。

①QTimer()の()内は何か入れないといけませんか?入れないといけないのであれば何を入れたらいいのか教えてください
②これは処理を止めない限り処理Xと処理Yが0.1秒ごとに繰り返されますか?
③もし②の回答が「はい」であった場合、処理Xが1秒以上かかる処理であったらどんなことが起きますか?(抽象的な質問で申し訳ありません)
④もし②の回答が「はい」であった場合、処理Xは「while 1:」を使ったループ関数にしなくてもループしますか?

素人丸出しのとんでもない質問で大変申し訳ありませんが、教えてくださると幸いです。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

QTimer()の()内は何か入れないといけませんか?

なにも入れなくてよいです。

これは処理を止めない限り処理Xと処理Yが0.1秒ごとに繰り返されますか?

今のコードはそうなっていません。
QTimer() は名前の通り、ストップウォッチです。
start() に指定したミリ秒分経過すると、timeout() シグナルが呼ばれます。
timeout() シグナルをスロットに繋いである場合は、タイムアウトしたときにその関数が呼ばれます。


本来どのようなことが行いたかったのかコメントいただければアドバイスできるかもしれません。

追記

今のコードでは、「処理Xが実行された0.1秒後に処理Xは止まり、処理Yが実行される」という解釈でよろしかったでしょうか?

今のコードは X() を呼び出すと、なにも起こらずにただちに終了します。
本来やりたい意図は置いておいて、問題点がいくつかあるのでコメント形式で書きました。

python

1def X(self): 2 self.Y # 関数呼び出しになっていない self.Y() では? 3 timer=QTimer() 4 timer.timeout.comect(self.Y) # comect() は connect() のスペルミスでは? 5 time.start(100) # start() という関数はタイマーをスタートさせるだけでここで処理はブロックされない。このあと、すぐに関数を抜けて、timer 変数が破棄されてしまうので、ローカル変数ではなく、self.timer のように属性として持っておかないとまずい

サンプルコード

QTimer の使い方の例を以下に記載します。
「タイマースタート」をクリックすると、2秒ごとに on_timeout() が呼ばれます。

python

1import sys 2from PyQt5.QtWidgets import * 3from PyQt5.QtCore import * 4 5 6class MainWindow(QMainWindow): 7 def __init__(self): 8 super().__init__() 9 self.initUI() 10 11 def initUI(self): 12 widget = QWidget() 13 self.setCentralWidget(widget) 14 15 layout = QVBoxLayout() 16 widget.setLayout(layout) 17 18 # ボタンを配置する。 19 self.button = QPushButton("タイマースタート") 20 self.button.clicked.connect(self.startTimer) 21 layout.addWidget(self.button) 22 23 def startTimer(self): 24 self.timer = QTimer() 25 self.timer.timeout.connect(self.on_timeout) # QTimer が timeout した場合に呼び出す関数を登録 26 self.timer.start(2000) # タイマーをスタートさせる 27 28 def on_timeout(self): 29 """start() で設定したミリ秒ごとにこの処理が呼ばれます 30 """ 31 print("timeout") 32 33 34if __name__ == '__main__': 35 app = QApplication(sys.argv) 36 windows = MainWindow() 37 windows.show() 38 app.exec_() 39 sys.exit(0)

Whileは処理が重くなるため使ってはいけないのかと感じています。

GUI アプリケーションは、イベントが発生していないかチェックするイベントループというものがメインスレッドで動いています。
while やすぐに終了しない重たい処理を行ってしまうと、そのイベントループが止まってしまうので、GUI がフリーズしたようになります。
なので、while や重たい処理を行いたい場合は別にスレッドを作って行う必要があります。

追記

「物体を検知してドアを開閉する」処理と「ドアの開閉状態をテキストボックスに入力する」処理をマルチスレッド(threading)で並列処理する『処理Z』をつくればよろしいのでしょうか?

ドアの開閉を行う処理を別スレッドで行う必要があると思います。
図にすると以下のようになります。
ドアが開閉されたら、シグナルを発呼し、メインスレッド側のスロットで受信し、テキストボックスに開閉状態を表示すればよいと思います。

イメージ説明

python

1import sys 2from datetime import datetime 3from PyQt5.QtWidgets import * 4from PyQt5.QtCore import * 5 6### ここは別スレッドで行う ### 7class Worker(QObject): 8 doorOpened = pyqtSignal() 9 10 def __init__(self, parent=None): 11 QObject.__init__(self, parent=parent) 12 13 def process(self): 14 while True: 15 QThread.sleep(3) 16 # 実際はドアを開閉する処理などを書く 17 18 # ドアの開閉を通知 19 self.doorOpened.emit() 20 21class MainWindow(QMainWindow): 22 stop_signal = pyqtSignal() 23 24 def __init__(self): 25 super().__init__() 26 self.initUI() 27 28 def initUI(self): 29 widget = QWidget() 30 self.setFixedSize(640, 480) 31 self.setCentralWidget(widget) 32 33 layout = QVBoxLayout() 34 widget.setLayout(layout) 35 36 # LineEdit を配置する。 37 self.lineEdit = QLineEdit("処理開始") 38 layout.addWidget(self.lineEdit) 39 40 # スレッドを作成する。 41 self.thread = QThread() 42 43 # worker を作成し、メインスレッドから先程作成したスレッドに移す。 44 self.worker = Worker() 45 self.worker.moveToThread(self.thread) 46 47 # signal slot の設定 48 self.thread.started.connect(self.worker.process) # スレッド開始後に process() 開始 49 self.worker.doorOpened.connect(self.func) # doorOpened() が発呼されたら、func() を呼ぶ 50 51 # スレッドを開始 52 self.thread.start() 53 54 def func(self): 55 # ドアの開閉が通知されたら、テキストボックスに表示する 56 now = datetime.now() 57 self.lineEdit.setText(f"Door opened! {now}") 58 59### メインスレッド ### 60if __name__ == '__main__': 61 app = QApplication(sys.argv) 62 windows = MainWindow() 63 windows.show() 64 app.exec_() 65 sys.exit(0)

ここで詳解するのは、スペース的に厳しいので、概要と検索キーワードを示しておきます。

  • スレッド間のやり取り: Qt のシグナルスロットを使う

→ 検索キーワード「Qt シグナルスロット」

  • マルチスレッド: QThread を使う

→ 検索キーワード「QThread」

蛇足

ロボットのシステム開発だと、いくつかの処理を並列で実行しつつ、各処理間でデータをやり取りする必要があるので、システムが複雑になってくると、マルチスレッドのプログラムを書くのは大変になってきます。
なので、ROS というロボット用のフレームワーク (ライブラリ) がよく使われます。

投稿2020/05/21 08:48

編集2020/05/22 12:33
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pythonnoob1

2020/05/21 09:52

回答いただきありがとうございます。 こんなとんでも質問に回答なんかつかないのではないかと心配しておりました。 今のコードでは、「処理Xが実行された0.1秒後に処理Xは止まり、処理Yが実行される」という解釈でよろしかったでしょうか? 本来行いたかったことは、自動ドアのようなものを作りたいです。 処理Xで「物体を検知し、モーターでドアの開閉を行う」コードを処理Yで「ドアの開閉状況をテキストボックスに入力する」コードを作成したいと考えていました。 上のコードではテキストボックスはありませんが、後々追加するつもりでした。 追伸 少し前に、処理Xで「物体を検知し、モーターでドアを開閉する」コードをループ関数(While 1:)で実行し、停止ボタン(ドアを開閉するモーターが停止する)を押すと、GUI自体が固まってしまう状態になってしまいました。そのため、Whileは処理が重くなるため使ってはいけないのかと感じています。 私自身のやり方が間違っているのかもしれませんが、、、
tiitoi

2020/05/21 10:58 編集

追記しました。「ある処理を開始して 0.1 秒後に終了する」という処理を行いたい場合は while 内で処理を行いつつ、時刻を調べて 0.1 秒経過したら処理を終える関数を1つつくって、別スレッドで実行すればよいと思います。 GUI アプリケーションで while を使う場合、マルチスレッドで動かすことが必須です。 QTimer は、一定時間後に処理を終了するのではなく、一定時間ごとに同じ処理を繰り返し行う場合に使います。 追記: QTimer の仕様について一部勘違いしていたので、コメントを修正
pythonnoob1

2020/05/21 12:03

丁寧な回答と、ご指摘・訂正ありがとうございます!! 「物体を検知してドアを開閉する」処理と「ドアの開閉状態をテキストボックスに入力する」処理をマルチスレッド(threading)で並列処理する『処理Z』をつくればよろしいのでしょうか? いまいち、GUI アプリケーション上での while の使い方が理解できておりません。
tiitoi

2020/05/22 12:32

追記しました。「物体を検知してドアを開閉する」は別スレッドで実行する必要がありそうです。ドアが開閉したら、Qt のシグナルスロットを使い、メインスレッド側に通知し、テキストボックスに表示するという処理はメインスレッドで行うことになると思います。
pythonnoob1

2020/05/22 12:40

ありがとうございます!! ここまで丁寧にご教授いただき、申し訳なさと感謝で心がいっぱいです!! 本当に本当にありがとうございました!
Kazumori102

2021/01/26 14:35

GUI アプリケーションは、イベントが発生していないか~必要があります。 や、スレッドの話が役に立った。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問