QMdiArea, stop subwindows from leaving area

All we need is an easy explanation of the problem, so here it is.

Is it possible to avoid the effect of the subwindow being partially obscured?

QMdiArea, stop subwindows from leaving area

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

QMdiArea automatically installs its event filter on any new QMdiSubWindow, so you can override eventFilter(), check for geometry changes, and ensure that the geometry is always within the viewport rectangle.

In the following example I created a helper function to do so, which can also be called whenever the mdi area is resized, in order to ensure that windows are always visible even when the area is resized to a size that would potentially hide windows.

class MdiFixBoundaries(QtWidgets.QMdiArea):
    def fixGeometry(self, window, viewGeo):
        winGeo = window.geometry()
        if not viewGeo.contains(winGeo):
            if winGeo.right() > viewGeo.right():
                winGeo.moveRight(viewGeo.right())
            if winGeo.x() < 0:
                winGeo.moveLeft(0)

            if winGeo.bottom() > viewGeo.bottom():
                winGeo.moveBottom(viewGeo.bottom())
            if winGeo.y() < 0:
                winGeo.moveTop(0)
            if winGeo != window.geometry():
                window.setGeometry(winGeo)
                return True
        return False

    def eventFilter(self, obj, event):
        if (event.type() == event.Move and 
            isinstance(obj, QtWidgets.QMdiSubWindow) and
            self.fixGeometry(obj, self.viewport().geometry())):
                return True
        return super().eventFilter(obj, event)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        viewGeo = self.viewport().geometry()
        for win in self.subWindowList():
            self.fixGeometry(win, viewGeo)


app = QtWidgets.QApplication([])
mdi = MdiFixBoundaries()
for i in range(3):
    test = mdi.addSubWindow(QtWidgets.QWidget())
    test.resize(320, 240)
mdi.show()
app.exec()

Note: the ifs in fixGeometry() must be kept, without any elif and in that order, otherwise you’ll risk recursion in case the size of a window is bigger than the viewport.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply