Search code examples
pythonpython-3.xpyqtpyqt5qmdiarea

Center subwindows in qmdiarea


Is there an attribute to position subwindows in qmdiarea? I’m trying to center subwindow in middle of mainwindow on startup (mdiarea)

I’m working on a mcve but haven’t finished it, wanted to see if anyone has tried doing this, and how they did it

Subwindows are randomly placed on startup when initialized

class App(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent=parent)
        self.setupUi(self)
        self.screenShape = QDesktopWidget().screenGeometry()
        self.width = self.screenShape.width()
        self.height = self.screenShape.height()
        self.resize(self.width * .6, self.height * .6)
        self.new = []
#calls GUI's in other modules
        self.lw = Login()
        self.vs = VS()
        self.ms = MS()
        self.hw = HomeWindow()
        self.mw = MainWindow()
        self.ga = GA()
        self.sGUI = Settings()
# shows subwindow
        self.CreateLogin()
        self.CreateVS()
        self.CreateMS()
        self.CreateGA()
        self.CreateSettings()

    def CreateLogin(self):
        self.subwindow = QMdiSubWindow()
        self.subwindow.setWidget(self.lw)
        self.subwindow.setAttribute(Qt.WA_DeleteOnClose, True)
        self.mdiArea.addSubWindow(self.subwindow)
        self.subwindow.setMaximumSize(520, 300)
        self.subwindow.setMinimumSize(520, 300)
        self.lw.showNormal()

    def CreateVS(self):
        self.subwindow = QMdiSubWindow()
        self.subwindow.setWidget(self.vs)
        self.mdiArea.addSubWindow(self.subwindow)
        self.vs.showMinimized()

    def CreateMS(self):
        self.subwindow = QMdiSubWindow()
        self.subwindow.setWidget(self.ms)
        self.mdiArea.addSubWindow(self.subwindow)
        self.ms.showMinimized()
        self.ms.tabWidget.setCurrentIndex(0)

    def CreateGA(self):
        self.subwindow = QMdiSubWindow()
        self.subwindow.setWidget(self.ga)
        self.mdiArea.addSubWindow(self.subwindow)
        self.ga.showMinimized()
        self.subwindow.setMaximumSize(820, 650)

    def CreateSettings(self):
        self.subwindow = QMdiSubWindow()
        self.subwindow.setWidget(self.sGUI)
        self.mdiArea.addSubWindow(self.subwindow)
        self.sGUI.showMinimized()

    def CreateWindow(self):
        self.hw.pushButton.clicked.connect(self.vs.showNormal)
        self.hw.pushButton_2.clicked.connect(self.Moduleprogram)
        self.hw.pushButton_3.clicked.connect(self.ms.showNormal)
        self.hw.pushButton_4.clicked.connect(self.ga.showNormal)
        self.subwindow = QMdiSubWindow()
        self.subwindow.setWindowFlags(Qt.CustomizeWindowHint | Qt.Tool)
        self.subwindow.setWidget(self.hw)
        self.subwindow.setMaximumSize(258, 264)
        self.subwindow.move(self.newwidth*.35, self.newheight*.25)
        self.mdiArea.addSubWindow(self.subwindow)


Solution

  • In Qt the geometry is only effective when the window is visible so if you want to center something it must be in the showEvent method. On the other hand to center the QMdiSubWindow you must first get the center of the viewport of the QMdiArea, and according to that modify the geometry of the QMdiSubWindow.

    Because the code you provide is complicated to execute, I have created my own code

    from PyQt5 import QtCore, QtGui, QtWidgets
    import random
    
    
    def create_widget():
        widget = QtWidgets.QLabel(
            str(random.randint(0, 100)), alignment=QtCore.Qt.AlignCenter
        )
        widget.setStyleSheet(
            """background-color: {};""".format(
                QtGui.QColor(*random.sample(range(255), 3)).name()
            )
        )
        widget.setMinimumSize(*random.sample(range(100, 300), 2))
        return widget
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            add_button = QtWidgets.QPushButton(
                "Add subwindow", clicked=self.add_subwindow
            )
            self._mdiarea = QtWidgets.QMdiArea()
    
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
            lay = QtWidgets.QVBoxLayout(central_widget)
            lay.addWidget(add_button)
            lay.addWidget(self._mdiarea)
    
            self._is_first_time = True
    
            for _ in range(4):
                self.add_subwindow()
    
        @QtCore.pyqtSlot()
        def add_subwindow(self):
            widget = create_widget()
            subwindow = QtWidgets.QMdiSubWindow(self._mdiarea)
            subwindow.setWidget(widget)
            subwindow.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
            subwindow.show()
            self._mdiarea.addSubWindow(subwindow)
            # self.center_subwindow(subwindow)
    
        def showEvent(self, event):
            if self.isVisible() and self._is_first_time:
                for subwindow in self._mdiarea.subWindowList():
                    self.center_subwindow(subwindow)
                self._is_first_time = False
    
        def center_subwindow(self, subwindow):
            center = self._mdiarea.viewport().rect().center()
            geo = subwindow.geometry()
            geo.moveCenter(center)
            subwindow.setGeometry(geo)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())
    

    enter image description here

    Update:

    If you want the subwindow to be centered then with the following code you have to create a property center to True:

    def add_subwindow(self):
        widget = create_widget()
        subwindow = QtWidgets.QMdiSubWindow(self._mdiarea)
        subwindow.setWidget(widget)
        subwindow.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        subwindow.show()
        subwindow.setProperty("center", True) # <----
        self._mdiarea.addSubWindow(subwindow)
    
    def showEvent(self, event):
        if self.isVisible() and self._is_first_time:
            for subwindow in self._mdiarea.subWindowList():
                if subwindow.property("center"): # <---
                    self.center_subwindow(subwindow)
            self._is_first_time = False