问题
I have a QGraphicsScene
and its associated QGraphicsView
. I let the user create some shapes in the form of derived QGraphicsItem
s into that scene. I also want them to be movable by mouse. Clicking one or more items select them, and moving them around while the mouse button is pressed works. I inherited QGraphicsView to do this, and overrided mousePressedEvent
, mouseReleasedEvent
& mouseMoveEvent
to achieve this. When the user clicks, I am basically testing if an item (accessed through items()
which returns the items of the associated scene) is under the mouse with contains()
, and if it is then I am selecting it.
In the mouseMoveEvent
, I am using setPos()
on each item of the selection to move it relatively to the mouse move. It works and displays as expected.
This may not be the most efficient way, but that's what I achieved while discovering Qt. Now, the problem is : once I've moved my item or group of items with the mouse, if I want to deselect them (by clicking again on them), the contains()
method supplied with the position of the input acts as if the item wasn't moved. Example : I draw a rectangle in the upper left corner, and move it around to, say, the center of the view. Clicking on it again doesn't work but clicking on where it was initially works. So I suspect it has something to do with local and global coordinates.
I've run through several problems today (most of them resolved) but I'm stuck on this one.
Here's my View class :
class CustomGraphicsView(QGraphicsView):
def __init__(self, *args):
super().__init__(*args)
self.selection = []
self.offsets = []
self.select_point = None
def mousePressEvent(self, event):
pos = self.mapFromGlobal(event.globalPos())
modifiers = event.modifiers()
if event.button() == Qt.LeftButton:
#do something else
elif event.button() == Qt.RightButton:
self.select_point = pos
for s in self.selection:
if s.contains(pos): # deselect or drag
for s in self.selection: # construct the offsets for dragging
self.offsets = [s.pos() - pos for s in self.selection]
break
def mouseReleaseEvent(self, event):
pos = self.mapFromGlobal(event.globalPos())
modifiers = event.modifiers()
if event.button() == Qt.LeftButton:
#do something else
elif event.button() == Qt.RightButton:
if self.select_point == pos: # one click selection
self.update_selection(pos)
if self.offsets:
self.offsets.clear()
def mouseMoveEvent(self, event):
pos = self.mapFromGlobal(event.globalPos())
modifiers = event.modifiers()
if event.buttons() == Qt.RightButton:
if not self.offsets:
for s in self.selection:
self.offsets = [s.pos() - pos for s in self.selection]
for s, off in zip(self.selection, self.offsets):
s.set_pos(pos + off)
def update_selection(self, pos):
for item in self.items():
if not item.contains(pos):
continue
if item.selected:
self.selection.remove(item)
else:
self.selection.append(item)
item.select()
break
The scene rect is set at (0;0) so there's no concern about moving it or whatever.
来源:https://stackoverflow.com/questions/19668164/moving-qgraphicsitem-by-mouse-in-a-qgraphicsscene