Aquarius_Girl
Aquarius_Girl

Reputation: 22916

Mouse position in mouseMoveEvent and mousePressEvent are different: QGraphicsObject

Mouse position in mouseMoveEvent and mousePressEvent are different in the following example. This is happening due to the added scaling. Without scaling the positions are same.

Do I have to update the boundingRect according to the changed scaling? How?

#!/usr/bin/env python
from PyQt5.QtCore import (QRectF)
from PyQt5.QtGui import (QPainter, QPixmap)
from PyQt5.QtWidgets import (QMainWindow, QApplication, QGraphicsObject, QGraphicsView, QGraphicsScene)


class TicTacToe(QGraphicsObject):
    def __init__(self, helper):
        super(TicTacToe, self).__init__()
        self.mypixmap = QPixmap("exit1.png")

    def paint(self, painter, option, widget):
        painter.setOpacity(1)

        painter.drawPixmap(0,0, 512, 512, self.mypixmap)
        painter.drawLine(2,2,20,20)

    def boundingRect(self):
        return QRectF(0,0,512, 512)


    def keyPressEvent(self, event):
        print "aaaaaaaaaa"

    def mouseMoveEvent(self, event):
        print "ccccccccccc ", event.pos()

    def mousePressEvent(self, event):
        print "bbbbbbbbbbbb", event.pos()


class MyGraphicsView(QGraphicsView):
    def __init__(self):
        super(MyGraphicsView, self).__init__()
        self.scene = QGraphicsScene(self)

        self.tic_tac_toe = TicTacToe(self)

        self.myScale = 2
        self.tic_tac_toe.setScale(self.myScale)

        self.setScene(self.scene)
        self.scene.addItem(self.tic_tac_toe)
        self.setMouseTracking(True) 

    def keyPressEvent(self, event):
        self.tic_tac_toe.keyPressEvent(event)

    def mouseMoveEvent(self, event):
        print "mouse"        
        self.tic_tac_toe.mouseMoveEvent(event)


class Example(QMainWindow):    
    def __init__(self):
        super(Example, self).__init__()

        self.y = MyGraphicsView()
        self.setCentralWidget(self.y)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    w = Example()
    w.show()
    sys.exit(app.exec_())

Upvotes: 1

Views: 2990

Answers (1)

eyllanesc
eyllanesc

Reputation: 243955

The problem is caused because you are sending the QGraphicsView events to a QGraphicsObject. In the case of QGraphicsView the event is of the QMouseEvent type but in the case of QGraphicsObject it is of the QGraphicsSceneMouseEvent type. In conclusion, you should not pass the QGraphicsView events to the QGraphicsObject since they refer to different events with different information.

The mousePressEvent event is enabled by default but in the case of the mouseMoveEvent event it can not be handled by QGraphicsObject, instead you must use hoverMoveEvent but these will only work inside the boundingRect of the QGraphicsObject.

#!/usr/bin/env python
from PyQt5.QtCore import (QRectF)
from PyQt5.QtGui import (QPainter, QPixmap)
from PyQt5.QtWidgets import (QMainWindow, QApplication, QGraphicsObject, QGraphicsView, QGraphicsScene)


class TicTacToe(QGraphicsObject):
    def __init__(self, helper):
        super(TicTacToe, self).__init__()
        self.mypixmap = QPixmap("exit1.png")
        self.setAcceptHoverEvents(True)

    def paint(self, painter, option, widget):
        painter.setOpacity(1)
        painter.drawPixmap(0,0, 512, 512, self.mypixmap)
        painter.drawLine(2,2,20,20)

    def boundingRect(self):
        return QRectF(0,0,512, 512)

    def hoverMoveEvent(self, event):
        print("ccccccccccc ", event.pos())

    def mousePressEvent(self, event):
        print("bbbbbbbbbbbb", event.pos())


class MyGraphicsView(QGraphicsView):
    def __init__(self):
        super(MyGraphicsView, self).__init__()
        self.scene = QGraphicsScene(self)

        self.tic_tac_toe = TicTacToe(self)

        self.myScale = 2
        self.tic_tac_toe.setScale(self.myScale)

        self.setScene(self.scene)
        self.scene.addItem(self.tic_tac_toe)

class Example(QMainWindow):    
    def __init__(self):
        super(Example, self).__init__()

        self.y = MyGraphicsView()
        self.setCentralWidget(self.y)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    w = Example()
    w.show()
    sys.exit(app.exec_())

On the other hand, these points do not coincide with the position in the scene since those coordinates are relative to the item.

For you to understand better we could use the following analogy, let's say you are recording a scene with a camera, the camera's screen is like the QGraphicsView, the scene is the QGraphicsScene and the actors are the QGraphicsItems and QGraphicsObjects. Each of these elements has a different coordinate system.

In the case of QGraphicsView your QMouseEvent returns coordinates in units of pixels, if you want to convert it to coordinates of the scene you must use mapToScene().

In the case of the QGraphicsItem/QGraphicsObject have different coordinates to those of the scene, those are not affected by the transformations such as scale, rotation, etc. That is what is printing in the previous example. If you want to convert it to units of the scene you must use mapToScene().

In the following example I show all the impressions in units of the scene.

#!/usr/bin/env python
from PyQt5.QtCore import (QRectF)
from PyQt5.QtGui import (QPainter, QPixmap)
from PyQt5.QtWidgets import (QMainWindow, QApplication, QGraphicsObject, QGraphicsView, QGraphicsScene)


class TicTacToe(QGraphicsObject):
    def __init__(self, helper):
        super(TicTacToe, self).__init__()
        self.mypixmap = QPixmap("exit1.png")
        self.setAcceptHoverEvents(True)

    def paint(self, painter, option, widget):
        painter.setOpacity(1)
        painter.drawPixmap(0,0, 512, 512, self.mypixmap)
        painter.drawLine(2,2,20,20)

    def boundingRect(self):
        return QRectF(0,0,512, 512)

    def hoverMoveEvent(self, event):
        #print("hoverMoveEvent ", event.pos())
        print("hoverMoveEvent", self.mapToScene(event.pos()))

    def mousePressEvent(self, event):
        #print("mousePressEvent", event.pos())
        print("mousePressEvent", self.mapToScene(event.pos()))


class MyGraphicsView(QGraphicsView):
    def __init__(self):
        super(MyGraphicsView, self).__init__()
        self.scene = QGraphicsScene(self)
        self.setMouseTracking(True)

        self.tic_tac_toe = TicTacToe(self)

        self.myScale = 2
        self.tic_tac_toe.setScale(self.myScale)

        self.setScene(self.scene)
        self.scene.addItem(self.tic_tac_toe)

    def mouseMoveEvent(self, event):
        print("mouseMoveEvent", self.mapToScene(event.pos()))

class Example(QMainWindow):    
    def __init__(self):
        super(Example, self).__init__()
        self.y = MyGraphicsView()
        self.setCentralWidget(self.y)

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    w = Example()
    w.show()
    sys.exit(app.exec_())

If you want more information check the following links:

Upvotes: 5

Related Questions