【问题标题】:PyQT4: why does QDialog returns from exec_() when setVisible(false)PyQT4:为什么当setVisible(false)时QDialog从exec_()返回
【发布时间】:2016-09-22 12:12:53
【问题描述】:

我正在使用 Python 2.7 和 PyQT4。

我想隐藏一个模态 QDialog 实例,然后再显示它。然而,当 dialog.setVisible(false) 被调用(例如,使用 QTimer)时,dialog.exec_() 调用返回(带有 QDialog.Rejected 返回值)。

然而,根据http://pyqt.sourceforge.net/Docs/PyQt4/qdialog.html#exec,_exec() 调用应该阻塞,直到用户关闭对话框。

有没有办法在不返回 _exec() 的情况下隐藏对话框?

#!/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_())

PS1:此代码打印以下输出:

Hide Event
Dialog exited with status 0 :: 1 0

(不调用关闭事件)。

PS2:对于上下文,我正在尝试实现一个 SystemTrayIcon,它允许隐藏和恢复 QMainWindow(这部分很好)和可能的模式 QDialog,而无需关闭对话框。

谢谢!

【问题讨论】:

    标签: python pyqt pyqt4


    【解决方案1】:

    您可以通过调用基类方法来绕过QDialog.setVisible(隐式关闭对话框)的正常行为:

        def hide_dialog(self):
            # self.dialog.setVisible(False)
            QtGui.QWidget.setVisible(self.dialog, False)
    

    但是,最好连接到对话框的finished() 信号,而不是使用exec(),并在其closeEvent 中明确地reject() 对话框。

    #!/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_())
    

    【讨论】:

    • 感谢您的解决方法,但它并没有真正回答如何(如果可能)避免 exec_() 返回的问题。
    【解决方案2】:

    如果有人感兴趣,下面的代码为我提供了一种快速而简单的方法来规避问题,尽管它并不能真正回答问题。

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    """Extension of the QDialog class so that exec_() does not exit when hidden.
    
    Dialogs inheriting will only exit exec_() via close(), reject() or accept()
    """
    
    from PyQt4 import QtGui, QtCore
    from PyQt4.QtGui import *
    from PyQt4.QtCore import *
    
    class HideableQDialog(QDialog):
        def __init__(self, *args, **kwargs):
            super(HideableQDialog, self).__init__(*args, **kwargs)
            self._mutex = QMutex()
            self._is_finished = False
            self._finished_condition = QWaitCondition()
            self.finished.connect(self._finish_dialog)
    
        def _finish_dialog(self):
            self._is_finished = True
            self._finished_condition.wakeOne()
    
        def close(self):
            super(HideableQDialog, self).close()
            self._finish_dialog()
    
        def reject(self):
            super(HideableQDialog, self).reject()
            self._finish_dialog()
    
        def accept(self):
            super(HideableQDialog, self).accept()
            self._finish_dialog()
    
        def exec_(self):
            status = super(HideableQDialog, self).exec_()
            self._mutex.lock()
            condition_succedeed = False
            while not condition_succedeed and not self._is_finished:
                condition_succedeed = self._finished_condition.wait(self._mutex, 10)
                QApplication.processEvents()
            self._mutex.unlock()
    

    【讨论】:

      猜你喜欢
      • 2011-05-22
      • 2013-08-22
      • 2016-11-14
      • 2016-03-29
      • 1970-01-01
      • 2014-06-22
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多