PyQT4: why does QDialog returns from exec_() when setVisible(false)
<p>I'm using Python 2.7 and PyQT4.</p>

<p>I want to hide a modal QDialog instance and later on show it again. However, when dialog.setVisible(false) is called (e.g., using QTimer), the dialog.exec_() call returns (with QDialog.Rejected return value).</p>

<p>However, according to <a href="http://pyqt.sourceforge.net/Docs/PyQt4/qdialog.html#exec" rel="nofollow">http://pyqt.sourceforge.net/Docs/PyQt4/qdialog.html#exec</a>, the _exec() call should block until the user <em>closes</em> the dialog.</p>

<p>Is there a way to hide the dialog without _exec() returning?</p>

<pre><code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os
from PyQt4 import QtGui, QtCore


class MyDialog(QtGui.QDialog):
    def __init__(self, parent):
        QtGui.QDialog.__init__(self, parent)

    def closeEvent(self, QCloseEvent):
        print "Close Event"

    def hideEvent(self, QHideEvent):
        print "Hide Event"


class MyWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setWindowTitle("Main Window")
        button = QtGui.QPushButton("Press me", self)
        button.clicked.connect(self.run_dialog)

    def run_dialog(self):
        self.dialog = MyDialog(self)
        self.dialog.setModal(True)
        self.dialog.show()
        QtCore.QTimer.singleShot(1000, self.hide_dialog)
        status = self.dialog.exec_()
        print "Dialog exited with status {}".format(status), "::", QtGui.QDialog.Accepted, QtGui.QDialog.Rejected

    def hide_dialog(self):
        self.dialog.setVisible(False)
        # self.dialog.setHidden(True)


if __name__ == '__main__':
    app = QtGui.QApplication([])
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())
</code></pre>

<p>PS1: This code prints the following output:</p>

<pre><code>Hide Event
Dialog exited with status 0 :: 1 0
</code></pre>

<p>(the close event is not called).</p>

<p>PS2: For context, I'm trying to implement a SystemTrayIcon that allows to hide and restore a QMainWindow (this part is fine) and possibly its modal QDialog without closing the dialog.</p>

<p>Thanks!</p>

<p>You can bypass the normal behaviour of <code>QDialog.setVisible</code> (which implicitly closes the dialog), by calling the base-class method instead:</p>

<pre><code>    def hide_dialog(self):
        # self.dialog.setVisible(False)
        QtGui.QWidget.setVisible(self.dialog, False)
</code></pre>

<p>However, it might be preferrable to connect to the dialog's <code>finished()</code> signal, rather than using <code>exec()</code>, and explicitly <code>reject()</code> the dialog in its <code>closeEvent</code>.</p>

<pre><code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os
from PyQt4 import QtGui, QtCore

class MyDialog(QtGui.QDialog):
    def __init__(self, parent):
        QtGui.QDialog.__init__(self, parent)
        layout = QtGui.QHBoxLayout(self)
        for title, slot in ('Ok', self.accept), ('Cancel', self.reject):
            button = QtGui.QPushButton(title)
            button.clicked.connect(slot)
            layout.addWidget(button)

    def closeEvent(self, QCloseEvent):
        print "Close Event"
        self.reject()

    def hideEvent(self, QHideEvent):
        print "Hide Event"

class MyWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setWindowTitle("Main Window")
        button = QtGui.QPushButton("Press me", self)
        button.clicked.connect(self.run_dialog)

    def run_dialog(self):
        self.dialog = MyDialog(self)
        self.dialog.finished.connect(self.dialog_finished)
        self.dialog.setModal(True)
        self.dialog.show()
        QtCore.QTimer.singleShot(3000, self.dialog.hide)

    def dialog_finished(self, status):
        print "Dialog exited with status:", status

if __name__ == '__main__':

    app = QtGui.QApplication([])
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())
</code></pre>

python pyqt pyqt4