2016-09-22 83 views
1

我正在使用Python 2.7和PyQT4。PyQT4:爲什麼QDialog從exec_()返回setVisible(false)

我想隱藏一個模態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 

(close事件不被調用)。

PS2:對於上下文,我試圖實現一個SystemTrayIcon,允許隱藏和恢復一個QMainWindow(這部分是好的),並可能它的模態QDialog沒有關閉對話框。

謝謝!

回答

3

您可以通過調用基類的方法,而不是繞過QDialog.setVisible正常行爲(其中隱式地關閉對話框):

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

但是,它可能是preferrable連接到對話框的finished()信號,而不是使用exec(),並明確地reject()對話框在其closeEvent

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

感謝您的解決方法,但它並沒有真正回答如何(如果可能的話)避免exec_()返回的問題。 – mhernandez

+0

@mhernandez。看到我更新的答案。 – ekhumoro

0

如果有人有興趣,下面的代碼提供了一個快速和骯髒的方法來解決我的問題,但它並沒有真正回答這個問題。

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