繁体   English   中英

取消 QFileDialog 时如何停止子 window 关闭

[英]How to stop child window closing when a QFileDialog is cancelled

我有一个处理开放项目的父 class。 可以从调用父 function 来处理打开项目的子 window 打开项目。 但是,当从子 window 取消文件对话框时,整个应用程序将退出。

from PyQt5.QtCore import Qt, QDateTime
from PyQt5.QtWidgets import *
from PyQt5 import QtGui

class ParentWindow(QDialog):
    def __init__(self):
        super(ParentWindow, self).__init__()
        self.cw = None

        self.setFixedSize(300, 100)
        self.button = QPushButton('Open')
        self.button.clicked.connect(self.open)

        layout = QHBoxLayout()
        layout.addWidget(self.button)
        self.setLayout(layout)

        self.show()

    def open(self):
        fileDialog = QFileDialog(self, 'Projects')
        fileDialog.setFileMode(QFileDialog.DirectoryOnly)

        if fileDialog.exec():
            self.hide()
            name = fileDialog.selectedFiles()[0]
            if self.cw:
                self.cw.close()
            self.cw = ChildWindow(self, name)

class ChildWindow(QDialog):
    def __init__(self, parent, name):
        super(ChildWindow, self).__init__(parent)
        self.setFixedSize(500, 100)
        self.setWindowTitle(name)

        self.openButton = QPushButton('Open')
        self.openButton.clicked.connect(self.parent().open)

        layout = QHBoxLayout()
        layout.addWidget(self.openButton)
        self.setLayout(layout)

        self.show()

我无法弄清楚为什么在文件拨号中按下取消时程序不会返回子 window。 有没有办法让父母负责打开项目并解决这个问题?

The problem probably resides on the different event timings of both hide and show events: I suppose that, until the open function returns, Qt has not yet "registered" the child as a window that will check against the QApplication.quitOnLastWindowClosed() option,这意味着即使子 window 显示了一小部分时间,它仍然“认为”只有一个 window(父)。

根据您的要求,有两种可能:

  • 在应用程序实例上使用setQuitOnLastWindowClosed(False) ,记住在父 window(或任何其他您想要在关闭时退出的 window)的 CloseEvent 中调用quit
  • 使用QTimer.singleShot(1, self.hide) ,它应该足够延迟隐藏以避免这个问题;

第一个解决方案通常更好,我强烈建议您使用它。
我什至不确定使用一毫秒的延迟实际上是否足以允许向应用程序发出“新的 window 存在”通知:可能需要更高的数量,并且该值也可能是任意的,具体取决于各种条件(包括平台实现)。
根据源代码,一旦顶级小部件关闭,它就会检查所有QApplication.topLevelWidgets() ,但根据我的测试,该列表不会立即更新: ChildWindow 通常在show()一段时间后“出现”,但有时(通常 <2 ms 之后)它根本不会出现在列表中。

这是一个非常简单的修复:

def open(self):
    fileDialog = QFileDialog(self, 'Projects')
    fileDialog.setAttribute(Qt.WA_QuitOnClose, False)

甚至更简单:

def open(self):
    fileDialog = QFileDialog(self.sender(), 'Projects')

这里的问题是,每当关闭 window 时,Qt 就会检查是否还有其他 windows 也应该关闭。 在大多数情况下,如果满足这两个条件,它会自动关闭一个 window:

  1. WA_QuitOnClose属性已设置,并且
  2. 没有父级,或者父级被隐藏

不幸的是,在您的示例中,文件对话框和子 window 都是如此,这导致 windows 都被关闭。 另外,由于quitOnLastWindowClosed默认为true,应用程序也会自动退出。

上面的第一个修复通过确保至少一个 window 没有设置关闭时退出属性来工作,第二个通过确保文件对话框的父级始终是可见的 window 来工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM