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

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

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

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

4035閲覧

PyQtのループの中で待つ方法(time.sleepは使わずに)

dinosauria123

総合スコア25

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/11/19 02:23

編集2018/11/19 02:44

測定して10秒休み、また同じ測定をする、というプログラムをPyQt5で作っています。

最初休むのにtime.sleep(msec)を使ったら、GUIがフリーズすることがわかりました。

QTimerを使ってみて、連続して1秒間隔で数をカウントする次のコードでGUIは動きました。
GUI(MainWindow_ui.py)にはボタンが2つ、ラベルが1つあります。

python

1from PyQt5 import QtCore, QtWidgets 2import MainWindow_ui 3 4class MainWindow(QtWidgets.QMainWindow): 5 def __init__(self, parent=None): 6 QtWidgets.QWidget.__init__(self, parent) 7 self.ui = MainWindow_ui.Ui_MainWindow() 8 self.ui.setupUi(self) 9 10 self.ui.pushButton.pressed.connect(self.start) 11 self.ui.pushButton_2.pressed.connect(self.stop) 12 13 self.num = 0 14 15 def add(self): 16 # for i in range(1, 10): 17 self.num = self.num +1 18 self.ui.label.setText(str(self.num)) 19 20 def start(self): 21 self.timer = QtCore.QTimer(self) 22 self.timer.timeout.connect(self.add) 23 self.timer.start(1000) 24 25 def stop(self): 26 self.timer.stop() 27 28if __name__ == "__main__": 29 import sys 30 app = QtWidgets.QApplication(sys.argv) 31 w = MainWindow() 32 w.show() 33 34 sys.exit(app.exec_())

しかし、コメントを外してfor文を動かすと、このループの中では1秒待ちをしてくれません。
ループの中でも待つにはどうすればよいでしょうか。

StackOverflowにtime.sleepの代わりにQtTest.QTest.qWait(msecs)が使えるという回答もあったのですが、テスト用の関数で、途中でbreakする方法もわからないのでできれば使いたくないです。

stackoverflow

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

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

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

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

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

tachikoma

2018/11/19 02:35

1秒ごとに実行するaddではなく、関数の中で1秒待ちをしてくれるaddを作りたいということですか?
dinosauria123

2018/11/19 02:45 編集

すみません、10秒待ってから測定するプログラムです。time.sleep(10000)の代わりが欲しいです。
guest

回答1

0

ベストアンサー

註: これは『1秒ごとに処理を実行する方法』です。

次の二点によって達成できます。
0. タイマーのtimeoutシグナルとaddメソッドを前以て紐付ける
0. addメソッド内でタイマーを再度走らせる

Python

1 def __init__(self, parent=None): 2 ... 3 4 self._timer = QtCore.QTimer() 5 self._timer.timeout.connect(self._run) 6 7 self._start_button.pressed.connect( 8 lambda: self._timer.start(1000) 9 ) 10 self._stop_button.pressed.connect( 11 self._timer.stop 12 ) 13 14 def _run(self): 15 print('Run') 16 self._timer.start(1000)

あるいは、タイマーにインターバルを設定したり。

Python

1 self._timer = QtCore.QTimer() 2 self._timer.setInterval(1000) 3 self._timer.timeout.connect(self._run) 4 5 self._start_button.pressed.connect(self._timer.start) 6 self._stop_button.pressed.connect(self._timer.stop) 7 8 9 def _run(self): 10 print('Run')

こんなユーティリティ関数を用意しておいても便利かもしれません...
...と思いましたが、GCがtimerオブジェクトを回収してしまうようなので、やや運用は面倒です。

Python

1def cyclicRun(msec, startSignal, stopSignal, run): 2 timer = QtCore.QTimer() 3 timer.setInterval(msec) 4 5 startSignal.connect(timer.start) 6 stopSignal.connect(timer.stop) 7 8 timer.timeout.connect(run)

Python

1cyclicRun( 2 1000, self._start_button.pressed, self._stop_button.pressed, self._run 3)

質問編集を受けて

time.sleep(10000)の代わり

走らせたい処理をメソッドに閉じ込め、タイマーと紐づければ良いだけかと。

追記

Python

1from datetime import datetime 2 3from PyQt5.QtCore import * 4from PyQt5.QtWidgets import * 5 6 7class Main(QWidget): 8 def __init__(self, parent=None): 9 QWidget.__init__(self, parent) 10 11 self._check_timer = QTimer() 12 self._check_timer.timeout.connect(self._check) 13 self._check_timer.setInterval(20000) 14 15 self._layout = QVBoxLayout() 16 17 self._start_button = QPushButton('start') 18 self._layout.addWidget(self._start_button) 19 self._start_button.pressed.connect( 20 lambda: QTimer.singleShot(0, self._check) 21 ) 22 23 self._stop_button = QPushButton('stop') 24 self._layout.addWidget(self._stop_button) 25 self._stop_button.pressed.connect(self._check_timer.stop) 26 27 self.setLayout(self._layout) 28 29 30 def _check(self): 31 def check_n_times(n): 32 if n == 0: 33 print() 34 return 35 36 print(f'{datetime.now().strftime("%M.%S.%f")} check once') 37 QTimer.singleShot(1000, lambda: check_n_times(n-1)) 38 39 check_n_times(10) 40 self._check_timer.start() 41 42 43if __name__ == "__main__": 44 import sys 45 app = QApplication(sys.argv) 46 47 m = Main() 48 m.show() 49 50 sys.exit(app.exec_())

実行イメージ

plain

125.16.160331 check once 225.17.189607 check once 325.18.189929 check once 425.19.190254 check once 525.20.190572 check once 625.21.190903 check once 725.22.191227 check once 825.23.191553 check once 925.24.191876 check once 1025.25.192206 check once 11 1225.36.182811 check once 1325.37.183130 check once 1425.38.183461 check once 1525.39.183786 check once 1625.40.184114 check once 1725.41.184437 check once 1825.42.185751 check once 1925.43.186082 check once 2025.44.186401 check once 2125.45.186736 check once

あんまり上手く書けませんでした。

  • stopを押しても、即座には停止してくれない
  • ワンセットの検査に要する秒数は20000msに決め打ち

とりあえず動作はします。

投稿2018/11/19 02:47

編集2018/11/19 07:28
LouiS0616

総合スコア35660

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

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

dinosauria123

2018/11/19 03:47

ありがとうございます。time.sleep(10000)の代わり の方もサンプルコードで示していただけますか。 start =>do something =>10秒待ち=>do again =>10秒待ち=>......(途中でstop)
LouiS0616

2018/11/19 03:50

10000ミリ秒ごとに処理を走らせたいのだったら、回答前半のコードでいけるはずです。
dinosauria123

2018/11/19 04:45

ありがとうございます。10秒おきはtimer.setInterval(msec)で確かにいけました。 ちょっと考え違いをしてまして、実はインターバルが二種類あって、10秒待った後に1秒おきに測定10回、が正しいです。一番上の例の1000ミリ秒のどちらかを10000ミリ秒に変えればうまくいきますかね。
LouiS0616

2018/11/19 04:50

回答の冒頭のコードでは、『1000』という数が二回出てきます。 そしてそれぞれが『最初の待ち時間』あるいは『インターバル』に対応しています。
dinosauria123

2018/11/19 04:55

ありがとうございます。こちらでやってみます。
dinosauria123

2018/11/19 06:18

For文の中でTimerは使えない(Timerの設定を反映しない)ようです。 For文なしでも書けるのでしょうが、難しそうです。
LouiS0616

2018/11/19 06:20

for文を置かなくても動作すると思うのですが。 提示したコードを実際に動かしてみて、ご希望の動作であるか確認してみると良いかと。 互いの理解に齟齬が出ているのかもしれません。
dinosauria123

2018/11/19 06:38

ありがとうございます。お手数をおかけします。 ループの中で待つtime.sleepのような関数があれば、既存のプログラムを大きく変更しなくて済むのですが.. ご提示のコードでは、最初に10秒待って1秒おきに測定することはできたのですが、実際にはそれを数回繰り返す必要があります。
LouiS0616

2018/11/19 06:46

『数回繰り返す』とは、『stopボタンを押すまで』という意味ですか? それとも、何回繰り返すか指定しておきたいのでしょうか。
dinosauria123

2018/11/19 06:50

すみません。『stopボタンを押すまで』になります。指定ならば、QtTest.QTest.qWait(msecs)でできるのですが。
LouiS0616

2018/11/19 06:59 編集

・startボタンを押すと、検査が開始される ・一回の検査は、次のように行われる。 __・10秒待つ __・1秒ごとに10回、何らかをチェック ・検査はstopボタンを押すまで続けられる こういうことですかね。 検査の衝突を考えると、一回の検査が終わった時にシグナルを発してもらう必要があるような... 一回の検査秒数を決め打つのも一つの手ではありますが。
dinosauria123

2018/11/19 07:09 編集

ありがとうございます。先に10回測定、10秒待ちとなりますが本質は変わりません。sleepできれば、検査の終わりに置いとけばよいのですが。 あるいはThreadを使う(まだ知識がないのですが)必要がありますかね。 Stopはあるいはアプリケーションの終了でもよいかなと思い始めています。(きれいじゃないですが)
LouiS0616

2018/11/19 07:32

いちおう書いてみました。ちょっと汚いですが、参考までに。 --- > sleepできれば、検査の終わりに置いとけばよいのですが。 シグナル/スロットの仕組み上、『その場でn秒止める』のは難しそうです。 --- > あるいはThreadを使う(まだ知識がないのですが)必要がありますかね。 sleepしたいのなら必須ですが、マルチスレッドにすると結構気を張ります。 ただし今後の拡張に依っては、早い段階で取り入れた方が良いかもしれません。
dinosauria123

2018/11/19 07:33

ありがとうございます。これをベースに拡張してみます。お手数おかけしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問