12
votes

I'm trying to make sense of QGraphicsView and QGraphicsScene, specifically how to place graphics items and have them appear where I want them to. I'm also confused about when scroll bars will appear if the scene is larger than the viewing area.

For example, this bit of code will create a small graphics view with an ellipse in the top corner:

import sys
from PyQt4 import QtGui, QtCore

class MyView(QtGui.QGraphicsView):
    def __init__(self):
        QtGui.QGraphicsView.__init__(self)

        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setSceneRect(QtCore.QRectF(0, 0, 245, 245))

        self.setScene(self.scene)

        self.item = QtGui.QGraphicsEllipseItem(0, 0, 60, 40)
        self.scene.addItem(self.item)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    view = MyView()
    view.show()
    sys.exit(app.exec_())

However, if the self.scene.setSceneRect(QtCore.QRectF(0, 0, 245, 245)) is omitted, then the ellipse appears in the middle of the window even though the ellipse has x,y = 0,0. I'm not sure why! Is there a reason for this behavior?

Likewise, I'm confused about the appearance of scrollbars when the scene size is larger than the view. For example, the following code creates a view/scene with several ellipses, and the itemsBoundingRect is larger than the sceneRect. Only some of the ellipses are shown, but there is no scrollbar to see the hidden ones, you have to increase the size of the window. But when you do that, the placement of the ellipses shifts, so the x,y of the ellipses are ignored.

import sys
from PyQt4 import QtGui, QtCore

class MyView(QtGui.QGraphicsView):
    def __init__(self):
        QtGui.QGraphicsView.__init__(self)

        self.setGeometry(QtCore.QRect(100, 100, 250, 250))

        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setSceneRect(QtCore.QRectF(0, 0, 200, 200))

        self.setScene(self.scene)

        for i in range(5):
            self.item = QtGui.QGraphicsEllipseItem(i*75, 10, 60, 40)
            self.scene.addItem(self.item)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    view = MyView()
    view.show()
    sys.exit(app.exec_())

If the self.scene.setSceneRect(QtCore.QRectF(0, 0, 200, 200)) line is omitted, then a scrollbar appears. But again, the x,y positions of the ellipses are ignored, and they are centered in the view.

What I am trying to do is: create a view where the items go where I want them, and if the number of items causes the scene to be larger than the view size, for scrollbars to appear but for the x,y positions of the objects to be maintained.

I feel like I'm missing some important piece of the view/scene puzzle...

2
Up voted for the first Q words: "I'm trying to make sense" :) :) :)amotzg

2 Answers

4
votes

From the document

If the scene rect is unset, PySide.QtGui.QGraphicsScene will use the bounding area of all >items, as returned by PySide.QtGui.QGraphicsScene.itemsBoundingRect() , as the scene rect.

So it's setting the rect of your image as your scene rect and the center of the scene is the center of the widget.

The scroll bars will appear when the scene rect is larger than the widget size. When you comment out the setSceneRect line your scene is being resized automatically but when you have the line your images are being added past the bounds of the scenRect so you would have to update your sceneRect to show it.

2
votes
import sys 
from PyQt4 import QtGui, QtCore

class MyView(QtGui.QGraphicsView):
    def __init__(self):
        QtGui.QGraphicsView.__init__(self)

        self.setGeometry(QtCore.QRect(100, 100, 600, 250))

        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setSceneRect(QtCore.QRectF())

        self.setScene(self.scene)

        for i in range(5):
            self.item = QtGui.QGraphicsEllipseItem(i*75, 10, 60, 40)
            self.scene.addItem(self.item)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    view = MyView()
    view.show()
    sys.exit(app.exec_())