PyQt5: I can't understand QGraphicsScene's setSceneRect(x, y, w, h)
Asked Answered
T

1

6

I see some people say if you want to put QGraphicsScene's origin of coordinates at the origin of QGraphicsView, i.e. top-left corner. You need to let both of them have the same size.

So here is what I do:

import sys
from PyQt5.QtWidgets import QApplication, QGraphicsLineItem, 
QGraphicsScene, QGraphicsView


class Demo(QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.line = QGraphicsLineItem()
        self.line.setLine(0, 0, 100, 100)

        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 300, 300)
        self.scene.addItem(self.line)

        self.setScene(self.scene)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

The View's size is 300x300 and I use setSceneRect() to make sure the Scene's size is 300x300.

In this case, the Scene's origin is at top-left corner. enter image description here

However, when I use setSceneRect(0, 0, 150, 150), the origin is not there, but at (75, 75)! enter image description here

Why? I thought the first two parameters of setSceneRect(x, y, w, h) set where the origin of coordinates should be. When the Scene is smaller than View, how can we make sure the Scene's origin is at the top-left corner?

Any help would be appreciated!

Tackling answered 21/4, 2019 at 7:48 Comment(2)
Try with setAlignment: doc.qt.io/qt-5/qgraphicsview.html#alignment-propIgnatius
It's workable. Thanks. But what are x, y used for in setSceneRect()? They seem not to be applied on the parent i.e. QGraphicsView's coordinates.Tackling
U
5

As the docs point out:

alignment : Qt::Alignment

This property holds the alignment of the scene in the view when the whole scene is visible.

If the whole scene is visible in the view, (i.e., there are no visible scroll bars,) the view's alignment will decide where the scene will be rendered in the view. For example, if the alignment is Qt::AlignCenter, which is default, the scene will be centered in the view, and if the alignment is (Qt::AlignLeft | Qt::AlignTop), the scene will be rendered in the top-left corner of the view.

So, by default, the scenerect is centered with the viewport of the QGraphicsView, and in the case of having the same size, the behavior you point out is observed, but in the second case the property of the centering is highlighted.

So the solution is to establish the alignment to:

import sys
from PyQt5.QtWidgets import QApplication, QGraphicsLineItem, QGraphicsScene, QGraphicsView
from PyQt5.QtCore import Qt

class Demo(QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.line = QGraphicsLineItem()
        self.line.setLine(0, 0, 100, 100)

        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 150, 150)
        self.scene.addItem(self.line)

        self.setScene(self.scene)
        self.setAlignment(Qt.AlignTop | Qt.AlignLeft)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

enter image description here


Explanation:

To understand what the scenerect is first, it must be understood that it is the QGraphicsView and the QGraphicsScene, these concepts are explained with an analogy to the recording of a movie, the QGraphicsView would be the camera, the QGraphicsScene represents what is recorded, ie the scene. The scene is delimited by the sceneRect, if the camera is very close to the scene, its limits will not be observed, but if the camera is far away, the scenerect projection in the camera will not occupy the whole screen, so it will have to be aligned in some position, in the case of QGraphicsView the alignment property is used.


why the scene is no longer centered in the view if I use setSceneRect(50, 50, 150, 150)?

To answer I use the following example where to make the scenerect visible I use a QGraphicsRectItem:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Demo(QtWidgets.QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.line = QtWidgets.QGraphicsLineItem()
        self.line.setLine(0, 0, 100, 100)

        self.scene = QtWidgets.QGraphicsScene()
        self.scene.setSceneRect(50, 50, 150, 150)
        self.scene.addItem(self.line)
        rect_item = self.scene.addRect(QtCore.QRectF(50, 50, 150, 150))
        rect_item.setPen(QtGui.QPen(QtGui.QColor("green")))

        self.setScene(self.scene)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

enter image description here

As you can see the alignment is not about QRectF(0, 0, w, h) but the center of QRectF(x, y, w, h) which in this case is (100,100). So keep centered on sceneRect in the QGraphicsView.

Unable answered 21/4, 2019 at 7:59 Comment(10)
It's workable. Thanks. But what are x, y used for in setSceneRect()? They seem not to be applied on the parent---QGraphicsView's coordinates.Tackling
@just_be_happy The parent of QGraphicsScene is not QGraphicsView, it seems that you do not know what the coordinate system means in these elements. With an analogy it is easy to understand, for example consider the recording of a movie, the QGraphicsView is the camera, the QGraphicsScene is what is recorded(the world), but in this case that world is delimited by the sceneRect, but as you see it in the QGraphicsView depends how far is the camera from the scene, so many times the scene will not occupy the whole screen of the camera so it will have to be aligned somewhere in the screenUnable
Allow me to make it more clear: if I use setSceneRect(50, 50, 150, 150), it seems the scene is not in the center of the view. Why? the x, y must have a reference. If it's not the coordinates of QGraphicsView. What is it?Tackling
Thank you very much for the examples. It might take some time for me to process. But can you tell me why the scene is no longer centered in the view if I use setSceneRect(50, 50, 150, 150)?Tackling
Appreciate your help. I will go process them.Tackling
well, I now see that x, y are used as the reference for QGraphicsItem...Tackling
@just_be_happy Not necessarily, the position of a QGraphicsItem is relative to the coordinate system of the parent, and if it does not have a parent it will be relative to the coordinates of the scene: doc.qt.io/qt-5/qgraphicsitem.html#posUnable
Yes. Thank you very much.Tackling
@just_be_happy I recommend reading the docs since Qt is one of the best documented libraries.Unable
Well, I’ve spent some time reading the doc before I come here for help. But the doc is useful indeed.Tackling

© 2022 - 2024 — McMap. All rights reserved.