[PyQt] QMdiArea persistence issue with closed windows

Hans-Peter Jansen hpj at urpla.net
Wed Oct 13 22:43:04 BST 2010


On Wednesday 13 October 2010, 21:30:08 Phil Thompson wrote:
> On Wed, 13 Oct 2010 15:44:58 +0200, "Hans-Peter Jansen"
> <hpj at urpla.net>
>
> wrote:
> > Hi Phil,
> >
> > while looking at dynamic resizing widgets on irc, David Boddie
> > created a
> >
> > small script, that I improved a little bit, which shows a small bug
> > with mdi windows. According to the doc of QMdiArea::addSubWindow,
> > closing windows should stay hidden, but if you close the mdi
> > window, and adds another button, it tracebacks with:
> >
> > Traceback (most recent call last):
> >   File "dynresize.py", line 29, in addRow
> >     if self.subwindow.isHidden():
> > RuntimeError: underlying C/C++ object has been deleted
>
> The docs say that a closed window will be hidden if you are passing
> your own QMdiSubWindow. It isn't really clear about what happens when
> you pass a QWidget. If you look at the C++ implementation of
> addSubWindow() you see that it is setting WA_DeleteOnClose in this
> case. So I think the current behaviour is correct.

Ah, I see, thanks.

For the sake of completeness, here's the fixed example, taking this 
insight into account. It needs an extra show() on the subwindow widget 
(iow the frame) to operate properly. Hrmpf. The trolls seem to play 
games with the subwindow widget state. Searching for isWidgetHiddenByUs 
in qmdisubwindow.cpp is quite informative in this regard. Oh, well.. 
Not your concern at least.

#!/usr/bin/env python

from PyQt4.QtCore import Qt, QTimer
from PyQt4.QtGui import *
import os, sys

class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self._buttonNr = 1

        self.mdi = QMdiArea()
        frame = QFrame()
        frameLayout = QVBoxLayout(frame)
        self.subwindow = QMdiSubWindow()
        self.subwindow.setWidget(frame)
        self.mdi.addSubWindow(self.subwindow)

        button = QPushButton("Add button")
        button.clicked.connect(self.addRow)

        layout = QVBoxLayout(self)
        layout.addWidget(self.mdi)
        layout.addWidget(button)

    def addRow(self):
        if self.mdi.activeSubWindow() is None:
            self.subwindow.show()
            self.subwindow.widget().show()

        button = QPushButton("Remove button %i" % self._buttonNr)
        button.clicked.connect(self.delRow)
        self._buttonNr += 1
        self.subwindow.widget().layout().addWidget(button)
        QTimer.singleShot(0, self.subwindow.adjustSize)

    def delRow(self):
        button = self.sender()
        button.hide()
        self.subwindow.widget().layout().removeWidget(button)
        button.deleteLater()
        QTimer.singleShot(0, self.subwindow.adjustSize)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())


Thanks,
Pete


More information about the PyQt mailing list