PyQt5: I cant understand QGraphicsScenes setSceneRect(x, y, w, h)

2024/7/4 17:05:31

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, QGraphicsViewclass 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!

Answer

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 Qtclass 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, QtWidgetsclass 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.

https://en.xdnf.cn/q/73386.html

Related Q&A

Remove first character from string Django template

I know this has been asked multiple times but the solution that everyone reaches (and the documentation) doesnt seem to be working for me...Trying to remove first characterCode is {{ picture.picture_pa…

Prevent Python logger from printing to console

Im getting mad at the logging module from Python, because I really have no idea anymore why the logger is printing out the logging messages to the console (on the DEBUG level, even though I set my File…

How to remove python assertion when compiling in cython?

so, here is my problem: I code in python, but I need to improve performance in some part of my code that are too slow. A good(and easy) solution seems to be using cython; I tried it and got good result…

ignoring newline character in regex match

I am trying to replace all matching occurrences with title cases using the following script. When there is a newline character between filter words (in this case ABC and DEF) that line doesnt get repla…

Xml parsing from web response

Im trying to get response from nominatim to geo-code few thousands of cities. import os import requests import xml.etree.ElementTree as ETtxt = open(input.txt, r).readlines() for line in txt:lp, region…

How to Install rpy2 on Mac OS X

I am trying, so far unsuccessfully, at installing the rpy2 for python on my Mac OSX. I have tried Macports and DarwinPorts but have had no luck with import rpy2 within the python shell environment. I…

Socket.IO vs. Twisted [closed]

Closed. This question is opinion-based. It is not currently accepting answers.Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.Clo…

How do I make Django ManyToMany through queries more efficient?

Im using a ManyToManyField with a through class and this results in a lot of queries when fetching a list of things. Im wondering if theres a more efficient way.For example here are some simplified cla…

How do I structure my Python project to allow named modules to be imported from sub directories

This is my directory structure:Projects+ Project_1+ Project_2- Project_3- Lib1__init__.py # emptymoduleA.py- Tests__init__.py # emptyfoo_tests.pybar_tests.pysetpath.py__init__.py # emptyfoo.pybar.p…

Plotly - Adding Scatter Geo points and traces on top of Density Mapbox

I am trying to add a Scattergeo trace or overlay on top of a white-bg density mapbox to get a heat map over a generic USA states outline. The reason for my use of scattergeo is Id like to plot a star s…