PDA

View Full Version : QGraphicsView, change mouse click/move item button (left is default)



sQaT
10th December 2020, 00:46
Hello,

Im fairly new to the GraphicsScene and GraphicsView in PyQt5, im trying to wrap my head around how to use it efficiently, and i have just bumped into an issue.

I am looking for a way to change the default mousebutton that moves the items in the GraphicsView.

This is the way i would like the graphicsScene UI to work :



LeftMouse button click on Item = ItemClick signal (like a regular button widget would do)
RightMouse button click on Item = ItemLeftClick signal (open a context menu with a few options specific to the item)

RightMouse button click on Empty space = Open's context menu for GraphicsView (so far so good).

#here
LeftMouse button click on Empty space and drag select rubberband = This Can stay as currently is, clears selection on click then it selects any of the items inside the rubberband rectangle on mouse click release.

MiddleMouse button drag = If items selected, i want this button to be moving my items position.


so far im kinda unable to do this..

this is a snippet of my current mouse logic inside the QtWidgets.QGraphicsView class , im not sure what i would need to do to replace the default leftMouse drag behaviour.



def mousePressEvent(self, event):
if event.button() == QtCore.Qt.MiddleButton and event.modifiers() == QtCore.Qt.AltModifier:
self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
self.drag = True
self.prev_pos = event.pos()
self.setCursor(QtCore.Qt.SizeAllCursor)
elif event.button() == QtCore.Qt.LeftButton:
self.setDragMode(QtWidgets.QGraphicsView.RubberBan dDrag)

# This does not work as i wanted, it is only changing the mouse icon
elif event.button() == QtCore.Qt.MiddleButton:
# set hand icon..
self.setDragMode(QtWidgets.QGraphicsView.DragMode. ScrollHandDrag)
# print selected item position in scene.
for x in self.scene().selectedItems() :
print( x.scenePos() )

super(View, self).mousePressEvent(event)

def mouseMoveEvent(self, event):
if self.drag:
new_scale = self.matrix().m11()
delta = (self.mapToScene(event.pos()) - self.mapToScene(self.prev_pos)) * -1.0 * new_scale
center = QtCore.QPoint(self.viewport().width() / 2 + delta.x(), self.viewport().height() / 2 + delta.y())
new_center = self.mapToScene(center)
self.centerOn(new_center)
self.prev_pos = event.pos()
return
super(View, self).mouseMoveEvent(event)

def mouseReleaseEvent(self, event):
if self.drag:
self.drag = False
self.setCursor(QtCore.Qt.ArrowCursor)
super(View, self).mouseReleaseEvent(event)

if event.button() == QtCore.Qt.RightButton:
# Context Menu
menu = QtWidgets.QMenu()
save = menu.addAction('save')
load = menu.addAction('load')
selectedAction = menu.exec_(event.globalPos())

if selectedAction == save:
common.scene_save(self)
if selectedAction == load:
common.scene_load(self)

d_stranz
10th December 2020, 18:29
I am not a Python or PyQt expert, but based on my C++ experience, it you want to override the mouse behavior completely, you do not want to call the superclass handler. If you only want to partially override it, you handle those parts and only call the superclass method for the things you want to stay as-is. And if you want to be sure the event is "eaten" and not passed anywhere else, you return "true" from the event handler.

sQaT
11th December 2020, 10:32
Holy smoke i did it!
Thank you so much for the pointers mate, you where right .

The way i managed to do it is inside my QGraphicsView Class, i am handling the mousePress event and MouseMove event:
ill probably have to also override the default rubberband selection of the items and manually handle that, since i want to avoid the left click selection
in favour of left click on item is "click" .

i had to also turn off the default Class flag inside my QGraphicsItem:
#self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovabl e)

This way, i simply handle the positions manually.

, i still have a few things to fix, which im not quite sure im doing correctly, but this seems to work closer to the way i wanted.