QMdiArea,阻止子窗口离开区域

QMdiArea, stop subwindows from leaving area

是否可以避免子窗口被部分遮挡的效果?

QMdiArea 会自动在任何新的 QMdiSubWindow 上安装其事件过滤器,因此您可以覆盖 eventFilter()、检查几何变化并确保几何始终位于视口矩形内。

在下面的示例中,我创建了一个辅助函数来执行此操作,也可以在调整 mdi 区域大小时调用它,以确保 windows 始终可见,即使该区域调整为可能隐藏 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()

注意:fixGeometry() 中的 if 必须 保留,没有任何 elif 并且按照那个顺序,否则你会如果 window 的大小大于视口,则存在递归风险。