Search code examples
pythonpython-3.xqgraphicsviewqgraphicsscenepyside2

How to center widgets on scene QGraphicsScene


I want to align the scene in the middle. My problem is that when you open an application, widgets are aligned somehow below the middle, but after hovering over buttons or a label, the widgets are aligned in the middle. Can I fix this somehow? Is there any right way to align the scene in the middle of the view?

Here is the whole code of my application:

import sys
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setFixedSize(QSize(1080, 720))
        self.setWindowTitle('Graphics Scene')
        self.centralwidget = QWidget()
        self.setCentralWidget(self.centralwidget)

        self.mainview = QGraphicsView(self.centralwidget)
        self.mainview.setGeometry(QRect(0, 0, 1080, 720))

        alignment = Qt.Alignment(Qt.AlignVCenter, Qt.AlignHCenter)
        self.mainview.setAlignment(alignment)

        # Main Scene (1)
        self.mainScene = QGraphicsScene()
        self.mainview.setScene(self.mainScene)

        self.labelTitle = QLabel('Main Scene')
        self.labelTitle.setStyleSheet('''
            QLabel {
                font: 48px 'Calibri';
                color: #999;
            }
        ''')

        styleForButtons = ('''
            QPushButton {
                margin: 0 70px;
                padding: 5px 30px;
            }
        ''')

        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.buttonPlay = QPushButton('Play')
        self.buttonSettings = QPushButton('Settings')
        self.buttonCredits = QPushButton('Credits')
        self.buttonMainExit = QPushButton('Exit')

        self.buttonPlay.setStyleSheet(styleForButtons)
        self.buttonSettings.setStyleSheet(styleForButtons)
        self.buttonCredits.setStyleSheet(styleForButtons)
        self.buttonMainExit.setStyleSheet(styleForButtons)

        self.buttonPlay.setSizePolicy(sizePolicy)
        self.buttonSettings.setSizePolicy(sizePolicy)
        self.buttonCredits.setSizePolicy(sizePolicy)
        self.buttonMainExit.setSizePolicy(sizePolicy)

        self.itemLabelTitle = self.mainScene.addWidget(self.labelTitle)
        self.itemButtonPlay = self.mainScene.addWidget(self.buttonPlay)
        self.itemButtonSettings = self.mainScene.addWidget(self.buttonSettings)
        self.itemButtonCredits = self.mainScene.addWidget(self.buttonCredits)
        self.itemButtonMainExit = self.mainScene.addWidget(self.buttonMainExit)

        self.mainMenuLayout = QGraphicsGridLayout()

        self.mainMenuLayout.addItem(self.itemLabelTitle, 0, 0, alignment)
        self.mainMenuLayout.addItem(self.itemButtonPlay, 1, 0)
        self.mainMenuLayout.addItem(self.itemButtonSettings, 2, 0)
        self.mainMenuLayout.addItem(self.itemButtonCredits, 3, 0)
        self.mainMenuLayout.addItem(self.itemButtonMainExit, 4, 0)

        self.mainMenuWidget = QGraphicsWidget()
        self.mainMenuWidget.setLayout(self.mainMenuLayout)
        self.mainScene.addItem(self.mainMenuWidget)

def main():
    app = QApplication(sys.argv)
    win = MyWindow()
    win.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

UPD: uploaded screenshots of what i see

enter image description here

I want to understand why my application behaves so strangely: firstly, why the widgets are not aligned exactly in the center, secondly, why there is a shift


Solution

  • The problem is caused because the scene does not have a sceneRect() set so when the QGraphicsView is displayed it sets the size of the scene using the resolution of the screen as a basis so it can initially have a size to the boundingRect() of all the items so that is centered with respect to that size and not with respect to the part of the scene that is shown in the viewport(), just after passing over the scene with the mouse the update() method is called and it updates to the correct size. So one solution is to set the sceneRect() using the size of the widget in scene coordinates.

    self.mainScene.setSceneRect(QRectF(QPointF(), self.mainMenuWidget.sizeHint(Qt.PreferredSize))) 
    self.mainScene.addItem(self.mainMenuWidget)