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.
However, is there a way to simultaneously hold the mouse button pressed and call hover events of different items?
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()