3

In my application I have a QGraphicsScene where the user should be able to change the color of items by having the mouse button clicked and hover over the items.

Below is an example code which I borrowed from another question:

PyQt: hover and click events for graphicscene ellipse

from PyQt5 import QtGui, QtCore, QtWidgets

class MyFrame(QtWidgets.QGraphicsView):
    def __init__( self, parent = None ):
        super(MyFrame, self).__init__(parent)

        self.setScene(QtWidgets.QGraphicsScene())

        # add some items
        x = 0
        y = 0
        w = 15
        h = 15
        pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.green))
        brush = QtGui.QBrush(pen.color().darker(150))

        # i want a mouse over and mouse click event for this ellipse
        for xi in range(3):
            for yi in range(3):
                item = callbackRect(x+xi*30, y+yi*30, w, h)
                item.setAcceptHoverEvents(True)
                item.setPen(pen)
                item.setBrush(brush)
                self.scene().addItem(item)
                item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)

class callbackRect(QtWidgets.QGraphicsRectItem):
    '''
    Rectangle call-back class.
    '''

    def mouseReleaseEvent(self, event):
        # recolor on click
        color = QtGui.QColor(180, 174, 185)
        brush = QtGui.QBrush(color)
        QtWidgets.QGraphicsRectItem.setBrush(self, brush)

        return QtWidgets.QGraphicsRectItem.mouseReleaseEvent(self, event)

    def hoverMoveEvent(self, event):
        # Do your stuff here.
        pass

    def hoverEnterEvent(self, event):
        color = QtGui.QColor(0, 174, 185)
        brush = QtGui.QBrush(color)
        QtWidgets.QGraphicsRectItem.setBrush(self, brush)

    def hoverLeaveEvent(self, event):
        color = QtGui.QColor(QtCore.Qt.green)
        brush = QtGui.QBrush(color.darker(150))
        QtWidgets.QGraphicsRectItem.setBrush(self, brush)

if ( __name__ == '__main__' ):
    app = QtWidgets.QApplication([])
    f = MyFrame()
    f.show()
    app.exec_()

So, in this code the hovering methods are only called when there is no mouse button pressed. As stated in the documentation (for PySide) the mousePressEvent "decides which graphics item it is that receives mouse events" which in some way blocks mouse events for other items.

https://deptinfo-ensip.univ-poitiers.fr/ENS/pyside-docs/PySide/QtGui/QGraphicsItem.html?highlight=graphicsitem#PySide.QtGui.PySide.QtGui.QGraphicsItem.mouseMoveEvent

However, is there a way to simultaneously hold the mouse button pressed and call hover events of different items?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Tho Re
  • 195
  • 1
  • 2
  • 6
  • Explain better, your explanation is confusing, you want it to happen when the item is pressed and when the mouse is hovered the item – eyllanesc Sep 30 '17 at 21:43
  • So, I wanna click at a position next to the item and while I move the cursor over it (and the mouse button is still clicked) a hover event of this item shall be triggered. – Tho Re Sep 30 '17 at 23:31
  • I understand the event you want, what task do you want to do when it happens? – eyllanesc Sep 30 '17 at 23:41
  • The item simply should change its color during the hoverEnterEvent. Even though I am not sure if this really matters. – Tho Re Oct 01 '17 at 00:08

1 Answers1

1

The problem is the combination of events that makes the task complicated, you can propagate the mouseMoveEvent event but you can not do the same with hover events. A simple solution is to implement the logic in the method mouseMoveEvent of QGraphicsView as shown below:

class MyFrame(QtWidgets.QGraphicsView):
    def __init__( self, parent = None ):
        super(MyFrame, self).__init__(parent)    
        self.setScene(QtWidgets.QGraphicsScene())
        [...]

    itemsSelected = []
    def mouseMoveEvent(self, event):
        QtWidgets.QGraphicsView.mouseMoveEvent(self, event)
        items = self.items(event.pos())#, QtGui.QTransform())
        for item in self.itemsSelected:
            if item in items:
                item.enterColor()
            else:
                item.leaveColor()
        self.itemsSelected = items

class callbackRect(QtWidgets.QGraphicsRectItem):
    '''
    Rectangle call-back class.
    '''
    def enterColor(self):
        color = QtGui.QColor(0, 174, 185)
        brush = QtGui.QBrush(color)
        QtWidgets.QGraphicsRectItem.setBrush(self, brush)

    def leaveColor(self):
        color = QtGui.QColor(QtCore.Qt.green)
        brush = QtGui.QBrush(color.darker(150))
        QtWidgets.QGraphicsRectItem.setBrush(self, brush)

    def hoverEnterEvent(self, event):
        self.enterColor()

    def hoverLeaveEvent(self, event):
        self.leaveColor()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I understand the idea and probably it is the right way to go for it. But copying this code simply into the example code doesn't actually do anything. When I click and hover over an item nothing happens. – Tho Re Oct 05 '17 at 18:06
  • As you do not respond I forget to update my answer, the final answer is the union of my answer plus your answer. Try it again please. :P – eyllanesc Oct 05 '17 at 22:51