0

In my application QPushButton starts calculation which takes variable time to finish (from few milliseconds to few seconds). The same QPushButton can be used to stop calculation.

QPushButton is checkable. When QPushButton is pressed the QPushButton state is checked and when calculation finish the QPushButton automatically switches state to unchecked.

But when calculation takes few milliseconds QPushButton stays in checked state after calculation is finished. When calculation takes more than 100 milliseconds everything works as expected.

I suspect that there is race condition between events but couldn't figure it out.

Minimal reproducible example (the sleep represents duration of calculation):

import sys
import threading
from time import sleep
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import QThread
from PyQt5.QtCore import pyqtSignal


class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.button = QPushButton("Run")
        self.button.setCheckable(True)
        self.setCentralWidget(self.button)

        self.calculation_status = CalculationStatus()

        self.button.pressed.connect(self.button_clicked)
        self.calculation_status.finished.connect(self.on_calculation_finished)

    def button_clicked(self):
        if self.button.isChecked():
            self.button.setText('Run')
        else:
            self.button.setText('Stop running')

            threading.Thread(target=self.run, daemon=True).start()

    def run(self):
        sleep(0.001)
        self.calculation_status.finished.emit()

    def on_calculation_finished(self):
        self.button.setChecked(False)
        self.button.setText('Run')


class CalculationStatus(QThread):
    finished = pyqtSignal()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
user1281071
  • 875
  • 2
  • 13
  • 23
  • use signals and slots – eyllanesc Sep 16 '21 at 10:46
  • I am not sure for which part signals and slots should be used. I update the minimal reproducible example with what I thought is correct usage of signals and slot but it works the same. – user1281071 Sep 16 '21 at 14:25
  • @user1281071 emitting a QThread signal using a python Thread is completely pointless. The problem is that Qt uses thread affinity to see if the signal can be emitted directly or queued, and since CalculationStatus and MainWindow are in the same thread, it won't work. You already created a QThread, but you're not using it. Move the computation in its `run` override, and emit the signal from there, then call `self.calculation_status.start()` to run it. – musicamante Sep 16 '21 at 16:29

0 Answers0