Вы должны выполнить трудоемкую задачу в другом потоке и подать сигнал, что задача завершена. Чтобы закрыть QMessageBox, вы должны использовать метод accept ():
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_()
Обновление:
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"])