Reputation: 587
I have a parent class which handles opening projects. Projects can be opened from a child window which calls the parent function to handle opening the project. However, when a file-dialog is cancelled from the child window, the entire application exits.
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()
I can't figure out why the program won't return to the child window when cancel is pressed in the file-dialg. Is there a way to keep the parent responsible for opening projects and fix this issue?
Upvotes: 2
Views: 1707
Reputation: 120598
Here is a very simple fix:
def open(self):
fileDialog = QFileDialog(self, 'Projects')
fileDialog.setAttribute(Qt.WA_QuitOnClose, False)
or even simpler:
def open(self):
fileDialog = QFileDialog(self.sender(), 'Projects')
The issue here is that whenever a window is closed, Qt checks to see if any other windows should also be closed. In most cases, it will automatically close a window if these two conditions are met:
WA_QuitOnClose
attribute is set, andUnfortunately, in your example, this is true for both the file-dialog and the child window, which results in both windows being closed. In addition, since quitOnLastWindowClosed is true by default, the application will also automatically quit.
The first fix above works by ensuring at least one window does not have the quit-on-close attribute set, and the second works by ensuring the parent of the file-dialog is always a visible window.
Upvotes: 2
Reputation: 48260
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, meaning that even if the child window is shown for a fraction of time, it still "thinks" that there is only one window (the parent).
According to your requirements there are two possibilities:
setQuitOnLastWindowClosed(False)
on the application instance, remembering to call quit
in the CloseEvent of the parent window (or any other window for which you want to quit on close);QTimer.singleShot(1, self.hide)
, which should delay the hiding enough to avoid this problem;The first solution is usually better and I strongly suggest you to use it.
I'm not even sure that using a one-ms delay would be actually enough to allow the "a new window exists" notification to the application: it might be necessary a higher amount, and that value could also be arbitrary, depending on various conditions (including platform implementation).
According to the source code, as soon as a top level widget is closed it checks against all QApplication.topLevelWidgets()
, but according to my tests the list is not immediately updated: the ChildWindow usually "appears" some time after show()
, but sometimes (usually <2 ms after) it does not appear in the list at all.
Upvotes: 2