Search code examples
pythonpython-3.xpyqtpyqt5qgraphicsview

How to get cursor click position in QGraphicsItem coordinate system?


I have a QGraphicsScene with QGraphicsItem added to it. Suppose I clicked on a map image (QGraphicsItem) where green circle is drawn. How to get click position in terms of this QGraphicsItem and not QGraphicsScene coordinate system.

road_map

P.S. Please, don't write code with mouse event handling. Just how to map click position correctly. Thanks in advance.


Solution

  • The idea is to convert the coordinate with respect to the scene to a coordinate with respect to the item.

    - Override mousePressEvent in QGraphicsScene:

    using the mapFromScene() method of QGraphicsItem:

    from PyQt5 import QtCore, QtGui, QtWidgets
    import random
    
    class Scene(QtWidgets.QGraphicsScene):
        def __init__(self, parent=None):
            super(Scene, self).__init__(parent)
            pixmap = QtGui.QPixmap(100, 100)
            pixmap.fill(QtCore.Qt.red)
    
            self.pixmap_item = self.addPixmap(pixmap)
            # random position
            self.pixmap_item.setPos(*random.sample(range(-100, 100), 2))
    
    
        def mousePressEvent(self, event):
            items = self.items(event.scenePos())
            for item in items:
                if item is self.pixmap_item:
                    print(item.mapFromScene(event.scenePos()))
            super(Scene, self).mousePressEvent(event)
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        scene = Scene()
        w = QtWidgets.QGraphicsView(scene)
        w.resize(640, 480)
        w.show()
        sys.exit(app.exec_())
    

    - Override mousePressEvent in QGraphicsView:

    using the mapFromScene() method of QGraphicsItem with mapToScene():

    from PyQt5 import QtCore, QtGui, QtWidgets
    import random
    
    class View(QtWidgets.QGraphicsView):
        def __init__(self, parent=None):
            super(View, self).__init__(QtWidgets.QGraphicsScene(), parent)
            pixmap = QtGui.QPixmap(100, 100)
            pixmap.fill(QtCore.Qt.red)
    
            self.pixmap_item = self.scene().addPixmap(pixmap)
            # random position
            self.pixmap_item.setPos(*random.sample(range(-100, 100), 2))
    
    
        def mousePressEvent(self, event):
            items = self.items(event.pos())
            for item in items:
                if item is self.pixmap_item:
                    print(item.mapFromScene(self.mapToScene(event.pos())))
            super(View, self).mousePressEvent(event)
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        w = View()
        w.resize(640, 480)
        w.show()
        sys.exit(app.exec_())
    

    - Override mousePressEvent of QGraphicsItem:

    from PyQt5 import QtCore, QtGui, QtWidgets
    import random
    
    class PixmapItem(QtWidgets.QGraphicsPixmapItem):
        def mousePressEvent(self, event):
            print(event.pos())
            super(PixmapItem, self).mousePressEvent(event)
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        scene = QtWidgets.QGraphicsScene()
        w = QtWidgets.QGraphicsView(scene)
        pixmap = QtGui.QPixmap(100, 100)
        pixmap.fill(QtCore.Qt.red)
        item = PixmapItem(pixmap)
        scene.addItem(item)
        item.setPos(*random.sample(range(-100, 100), 2))
        w.resize(640, 480)
        w.show()
        sys.exit(app.exec_())