Cpt. Crazy
Cpt. Crazy

Reputation: 115

PyQt5: set coordinates for items in graphics scene

I have a scene = QGraphicsScene() and I added an ellipse via scene.addEllipse(100, 100, 10, 10, greenPen, greenBrush). The brush and the pen are set before. I add the QGraphicsScene right after to a QGraphicsView with MyGraphicsView.setScene(scene). All of this works except the position of the ellipse is always the center. The first 2 parameters in the addEllipse() function should be the coordinates (in this case 100, 100), but no matter what I put there, the ellipse is always in the center. Any ideas?

EDIT: now I added 3 ellipses like this (the one in the description deleted):

scene.addEllipse(10, 10, 10, 10, greenPen, greenBrush)
scene.addEllipse(-100, -10, 30, 30, bluePen, blueBrush)
scene.addEllipse(-100, -100, 60, 60, bluePen, blueBrush)

and my result is this: enter image description here

So clearly the coordinates work somehow, but I still don't get how exactly. Do I have to set an origin to the scene?

And if I do this:

particleList = scene.items()
print(particleList[0].x())
print(particleList[1].x())
print(particleList[2].x())

I get:

0.0
0.0
0.0

At this point I'm totally confused and I'd really appreciate some help.

Upvotes: 2

Views: 1413

Answers (1)

musicamante
musicamante

Reputation: 48519

An important thing that must be always kept in mind is that the position of a QGraphicsItem does not reflect its "top left" coordinates.

In fact, you can have a QGraphicsRectItem that has a QRectF positioned at (100, 100) but its position at (50, 50). This means that the rectangle will be shown at (150, 150). The position of the shape is relative to the position of the item.

All add[Shape]() functions of QGraphicsScene have this important note in their documentation:

Note that the item's geometry is provided in item coordinates, and its position is initialized to (0, 0).

Even if you create a QGraphicsEllipseItem with coordinates (-100, -100), it will still be positioned at (0, 0), and that's because the values in the addEllipse() (as with all other functions) only describe the coordinates of the shape.

Then, when a QGraphicsScene is created, its sceneRect() is not explicitly set, and by default it corresponds to the bounding rectangle of all items. When the scene is added to a view, the view automatically positions the scene according to the alignment(), which defaults to Qt.AlignCenter:

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.

This also means that if you have items at negative coordinates or with their shapes at negative coordinates, the view will still show the scene centered to the center of the bounding rect of all items.

So, you either set the scene sceneRect or the view sceneRect, depending on the needs. If the view's sceneRect is not set, it defaults to the scene's sceneRect.

If you want to display the items according to their position while also ensuring that negative coordinates are correctly "outside" the center, you must decide the size of the visible sceneRect and set it accordingly:

    boundingRect = scene.itemsBoundingRect()
    scene.setSceneRect(0, 0, boundingRect.right(), boundingRect.bottom())

Upvotes: 3

Related Questions