I am confused by Qt's coordinate handling in a QGraphicsScene. I'm using PySide6, and create a QGraphicsScene with movable QGraphicsRectItems. I would like to limit the items to the boundaries of the scene. There is an example in the PySide docs, but it does not work (the example is auto-translated from C++ to Python, but it does not work for me even after correcting the translation errors). I figured the general idea would be to monitor an item for movement, which can be done by implementing the itemChange event handler. A pseudo implementation (not bothering with the nitty gritty Qt details) would look like: def itemChange(newPosition): if newPosition.x < scene.x: newPosition.x = scene.x return newPosition I cannot figure out how to make this actually work. It seems like every graphics item has its own idea of origin, and I have not found the mapping function that will turn the item's coordinates into scene coordinates. I have tried mapToScene and mapFromItem. But I have reviewed several different questions on stackoverflow, but I still seem to be misunderstanding what's happening. A minimal working example with a square which prints out the X coordinates when the square is dragged. As you drag the rectangle to the left of the scene, I would expect at least one of the X values to approach zero. import sys from PySide6 import QtWidgets from PySide6.QtCore import QPointF, QRectF from PySide6.QtGui import QBrush, QColor, QPen from PySide6.QtWidgets import QApplication, QMainWindow, QGraphicsScene, QGraphicsRectItem, QGraphicsItem, QGraphicsView class BoundableItem(QGraphicsRectItem): def __init__(self, *args, **kwargs): super(BoundableItem, self).__init__(*args, **kwargs) # Our items are movable and they send geometry change events self.setFlag(QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsMovable) self.setFlag(QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemSendsGeometryChanges) def itemChange(self, change, value: QPointF): if change == QGraphicsItem.GraphicsItemChange.ItemPositionChange and self.scene(): print(f"X=> As passed: {value.x()} mapToScene: {self.mapToScene(value).x()} mapFromItem: {self.mapFromItem(self, value).x()}") return super(BoundableItem, self).itemChange(change, value) class MyWindow(QMainWindow): def __init__(self): super(MyWindow, self).__init__() # Basic window setup self.setWindowTitle("Bounding Test") self.setFixedSize(320, 320) # Set up a fixed-sized screen scene = QGraphicsScene(0, 0, 240, 240) scene.setBackgroundBrush(QBrush(QColor.fromRgb(24, 24, 48))) # Draw a border around the scene scene.addRect(scene.sceneRect(), QPen(QColor.fromRgb(255, 255, 255))) # A blue square, offset by 32 rect = BoundableItem(QRectF(32.0, 32.0, 32.0, 32.0)) rect.setBrush(QBrush(QColor.fromRgb(0, 0, 255))) scene.addItem(rect) # Make a graphics view for the scene self.view = QGraphicsView() self.view.setScene(scene) self.setCentralWidget(self.view) if __name__ == '__main__': app = QApplication() window = MyWindow() window.show() sys.exit(app.exec()) Here is an example, with the console output, after dragging the square out of the bounds: X=> As passed: -40.0 mapToScene: -79.0 mapFromItem: -40.0 To actually change what happens in itemChange(), I know that you need to return the desired position (QPointF), I just didn't do that for my example because I was trying to just print out the X coordinates. Continue reading...