0

If I create an application with a MainWindow and a QDialog and then open and close the dialog the main window remains open.

But if my QDialog starts a thread, and once this thread is finished I close the QDialog then my whole application closes.

On the simple app below you can reproduce my problem. It's ok if I open the dialog and close without launch the tread. But if I launch the thread and close the dialog after finished the application terminate.

Can you tell me where is my mistake?

import sys
from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow, QPushButton, QVBoxLayout
from PyQt5.QtCore import QThread, QObject, pyqtSignal
from time import sleep
from PyQt5.Qt import QLabel

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        button = QPushButton("Press me for a dialog!")
        button.clicked.connect(self.button_clicked)
        self.setCentralWidget(button)

    def button_clicked(self):
        my_dialog = myDialog(parent=self)
        my_dialog.exec()

class myDialog(QDialog):
    def __init__(self, parent=None):
        super(myDialog, self).__init__(parent)
        self.setWindowTitle('My dialog')
        self.button = QPushButton("Run long task")
        self.button.clicked.connect(self.run_long_task)
        self.message = QLabel("Long task not launched")
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.button)
        self.layout.addWidget(self.message)
        self.setLayout(self.layout)

    def run_long_task(self):
        self.message.setText('Long task running')
        self.thread = QThread()
        self.worker = LongTask()
        self.worker.long_task_finished.connect(self.long_task_finished)
        self.thread.started.connect(self.worker.work)
        self.worker.moveToThread(self.thread)
        self.thread.start()

    def long_task_finished(self):
        self.message.setText('Long task finished')

class LongTask(QObject):
    long_task_finished = pyqtSignal()

    def work(self):
        sleep(5)
        self.long_task_finished.emit()


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

Thanks for your help.

galio
  • 5
  • 3
  • Not sure if it'll make a difference, but it should be `my_dialog.exec_()` I believe. – Peter Nov 04 '21 at 16:02
  • Also for the record I recently had issues with threads randomly causing my window to close depending on how it was launched, in the end I went with `QRunnable` and made another class inheriting `QObject` to handle the signals. Everything I tried other than that had issues. – Peter Nov 04 '21 at 16:05
  • As I see here https://stackoverflow.com/a/22614643/13749996 there is no difference with Python 3 and PyQT5. And I've tested and there is the same result with my problem. – galio Nov 04 '21 at 16:06
  • 2
    @galio Always run your script in a console/command-window, so that you can see any tracebacks and/or qt error messages. In this case, will see that the script aborts with the message `QThread: Destroyed while thread is still running`. Thus, the solution to your problem is to add the line `self.thread.quit()` to the `long_task_finished` slot. – ekhumoro Nov 04 '21 at 17:29
  • @galio PS: you should also move the worker object to the thread *before* connecting any signals, otherwise you might run into [the issue discussed in the second half of this answer](https://stackoverflow.com/a/20818401/984421). – ekhumoro Nov 04 '21 at 17:44
  • first run it in console/terminal to see error messages. Without error message it is waste of time. – furas Nov 04 '21 at 20:03
  • 1
    @ekhumoro I didn't realize that the debug mode in my IDE might not show me all the errors... So thank you for taking the time to reply! – galio Nov 05 '21 at 08:57

0 Answers0