Как остановить закрытие дочернего окна при отмене QFileDialog - PullRequest
1 голос
/ 27 сентября 2019

У меня есть родительский класс, который обрабатывает проекты открытия.Проекты могут быть открыты из дочернего окна, которое вызывает родительскую функцию для обработки открытия проекта.Однако, когда файл-диалог отменяется из дочернего окна, завершается все приложение.

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()

Я не могу понять, почему программа не вернется в дочернее окно, когда нажата кнопка отмены вфайл-Dialg.Есть ли способ возложить на родителей ответственность за открытие проектов и устранить эту проблему?

Ответы [ 2 ]

0 голосов
/ 27 сентября 2019

Вот очень простое исправление:

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

или даже проще:

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

Проблема здесь в том, что всякий раз, когда окно закрывается, Qt проверяет, чтобы увидетьесли другие окна также должны быть закрыты.В большинстве случаев оно автоматически закроет окно, если будут выполнены эти два условия:

  1. установлен атрибут WA_QuitOnClose, и
  2. нетparent, или родитель скрыт

К сожалению, в вашем примере это верно как для файла-диалога, так и для дочернего окна, что приводит к закрытию обоих окон.Кроме того, поскольку quitOnLastWindowClosed по умолчанию имеет значение true, приложение также автоматически завершит работу.

Первое исправление, приведенное выше, работает, гарантируя, что хотя бы одно окно не имеет атрибута quit-on-closeустановить, а вторая работает, гарантируя, что родительский файл-диалога всегда будет видимым окном.

0 голосов
/ 27 сентября 2019

Проблема, вероятно, связана с различными временными интервалами событий hide и show: я предполагаю, что до возврата функции open Qt еще не "зарегистрировала" дочерний элемент как окно, которое будет проверятьпротив параметра QApplication.quitOnLastWindowClosed(), означающего, что даже если дочернее окно отображается в течение доли времени, оно все равно «думает», что существует только одно окно (родительское).

В соответствии с вашими требованиями есть две возможности:

  • использовать setQuitOnLastWindowClosed(False) в экземпляре приложения, не забывая вызывать quit в CloseEvent родительского окна (или любого другого окна, для которого вы хотитевыйти при закрытии);
  • использовать QTimer.singleShot(1, self.hide), что должно задержать достаточно сокрытие, чтобы избежать этой проблемы;

Первое решение обычно лучше иЯ настоятельно рекомендую вам использовать его.
Я даже не уверен, что использование задержки в одну мс было бы на самом деле достаточно, чтобы позволить приложению уведомлять «новое окно существует»: это может быть необходимоболее высокое значение, и это значение также может быть произвольным, в зависимости от различных условий (включая реализацию платформы).
Согласно исходному коду , как только закрывается виджет верхнего уровня, он проверяет всеQApplication.topLevelWidgets(), но, согласно моим тестам, список не обновляется сразу: ChildWindow обычно «появляется» через некоторое время после show(), но иногда (обычно <2 мс после) он не появляется всписок на всех. </p>

...