- 別スレッドで走っている計算処理の終了後、計算終了を通知するメッセージボックスを表示する
- 別スレッドでオーディオファイルを再生し、再生終了時にQWidgetを操作する
というような、サブスレッド終了後にウィジェットを非同期的に操作する処理を書いてみました。
実装方法としては、PyQtのシグナル/スロットを利用します。
具体的な実装の流れとしては、
QWidget
/QWindow
クラスを継承したクラスで、シグナルsignal=pyqtSignal()
をクラス変数として定義- スロット(値を受け渡す関数)を定義
- スロットをシグナルにつなぐ
signal.connect(self.slot)
- サブスレッド起動
- 呼び出し元のオブジェクトを渡しておく
- サブスレッドで条件に応じて
signal.emit()
となります。
実装
注意点として、仕様のためpyqtSignal()
オブジェクトはクラス変数でなければなりません。
# -*- coding: utf-8 -*- import sys import time import threading from PyQt5.QtWidgets import * from PyQt5.QtCore import pyqtSignal def subthread(caller, count): for k in range(count, 0, -1): caller.signal_countdown.emit(k) time.sleep(1) caller.signal_countdown.emit(0) caller.signal_message.emit() class MainWindow(QWidget): signal_message = pyqtSignal() signal_countdown = pyqtSignal(int) def __init__(self): super().__init__() layout = QVBoxLayout() self.setLayout(layout) self.flg = False self.button = QPushButton(f"Start thread") self.button.clicked.connect(self.on_change) layout.addWidget(self.button) # スロットとシグナルを接続 self.signal_message.connect(self.message) self.signal_countdown.connect(self.countdown) def message(self): QMessageBox.information(None, "Message", "subthread is terminated.") self.button.setText(f"Start thread") self.flg = False def countdown(self, value): self.button.setText(f"{value}") def on_change(self): if not self.flg: self.flg = True th = threading.Thread(target=subthread, args=(self, 3)) th.setDaemon(True) th.start() if __name__ == '__main__': app = QApplication(sys.argv) w = MainWindow() w.show() app.exit(app.exec_())