Pygmalion
Pygmalion

Reputation: 919

QMessageBox to block parent while calculation

I want to use QMessageBox to block its parent QDialog, while doing calculation. I came upon something like that, but this does not work.

msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle('Working ....')
msgBox.setText("Working, please wait ...")
msgBox.setStandardButtons(QtWidgets.QMessageBox.NoButton)
msgBox.exec_()

(doing some time consuming work)

msgBox.close()

What is wrong, how can I do it properly?

Upvotes: 1

Views: 257

Answers (1)

eyllanesc
eyllanesc

Reputation: 244132

You have to execute the time-consuming task in another thread and signal through a signal that the task is finished executing. To close the QMessageBox you must use the accept() method:

import threading

from PyQt5 import QtCore, QtWidgets


class Worker(QtCore.QObject):
    started = QtCore.pyqtSignal()
    finished = QtCore.pyqtSignal()

    def execute(self, func, args):
        threading.Thread(target=self._execute, args=(func, args,), daemon=True).start()

    def _execute(self, func, args):
        self.started.emit()
        func(*args)
        self.finished.emit()


def consuming_work(arg1, arg2):
    import time

    print(arg1, arg2)
    time.sleep(5)
    print("finish")


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    msgBox = QtWidgets.QMessageBox()
    msgBox.setWindowTitle("Working ....")
    msgBox.setText("Working, please wait ...")
    msgBox.setStandardButtons(QtWidgets.QMessageBox.NoButton)
    worker = Worker(msgBox)
    worker.finished.connect(msgBox.accept)
    worker.execute(consuming_work, ["Stack", "Overflow"])
    msgBox.exec_()

Update:

import threading

from PyQt5 import QtCore, QtWidgets


class WorkerMessageBox(QtWidgets.QMessageBox):
    started = QtCore.pyqtSignal()
    finished = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.finished.connect(self.accept)

    def execute(self, func, args):
        threading.Thread(target=self._execute, args=(func, args,), daemon=True).start()
        return self.exec_()

    def _execute(self, func, args):
        self.started.emit()
        func(*args)
        self.finished.emit()


def consuming_work(arg1, arg2):
    import time

    print(arg1, arg2)
    time.sleep(5)
    print("finish")


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    msgBox = WorkerMessageBox()
    msgBox.setWindowTitle("Working ....")
    msgBox.setText("Working, please wait ...")
    msgBox.setStandardButtons(QtWidgets.QMessageBox.NoButton)

    msgBox.execute(consuming_work, ["Stack", "Overflow"])

Upvotes: 2

Related Questions