Green Cell
Green Cell

Reputation: 4777

QGraphicsScene keep selection on empty selection marquee

I have a collection of QGraphicsItem inside a QGraphicsScene. I'm trying to get the behavior of holding ctrl key and deselect any items within a selection marquee. The problem is that the current selection will clear on a mouse press. Is there something I'm missing to prevent this?

The only thing I can think of is saving the current selection on mouse release, then restoring it on the next mouse pressed event. This doesn't seem very elegant though so I'm hoping to avoid this.

Upvotes: 2

Views: 715

Answers (1)

Green Cell
Green Cell

Reputation: 4777

This gives me the behavior I'm looking for. I know it's not the most efficient approach, so please let me know if this can still be improved!

# Override double click event so it doesn't clear selection
def mouseDoubleClickEvent(self, event):
    pass

def mousePressEvent(self, event):
    QtGui.QGraphicsView.mousePressEvent(self, event)

    # Save state of mouse button and any key modifiers
    self.mouseButton = event.button()
    self.modifiers = event.modifiers()

    # If a modifier key is held, don't clear the selection!
    if self.modifiers == QtCore.Qt.SHIFT or self.modifiers == QtCore.Qt.CTRL:
        if self.lastSelection:
            for item in self.lastSelection:
                item.setSelected(True)
    else:
        self.scene().clearSelection()

def mouseMoveEvent(self, event):
    QtGui.QGraphicsView.mouseMoveEvent(self, event)

    # Only apply if the left mouse button is being held down
    if self.mouseButton == QtCore.Qt.MouseButton.LeftButton:
        # Add items to current selection if shift is held down
        if self.modifiers == QtCore.Qt.SHIFT:
            sel = set( self.lastSelection ).union( set( self.scene().selectedItems() ) )
            for item in sel:
                item.setSelected(True)
        # Remove items from current selection if ctrl is held down
        elif self.modifiers == QtCore.Qt.CTRL:
            sel = set( self.lastSelection ).union( set( self.scene().selectedItems() ) )
            dif = set( self.lastSelection ).symmetric_difference( set( self.scene().selectedItems() ) )
            for item in sel:
                selectState = not (item not in self.lastSelection or item not in dif)
                item.setSelected(selectState)

def mouseReleaseEvent(self, event):
    QtGui.QGraphicsView.mouseReleaseEvent(self, event)

    # Reset values
    self.mouseButton = None
    self.modifiers = None
    self.lastSelection = self.scene().selectedItems() # Store last selected items

So now if I hold ctrl it will deselect items, holding shift will add to the selection, and a normal mouse click will just clear the selection as expected.

The only thing to add to this would be to include shift & ctrl to a single mouse click, but since holding ctrl does add AND remove then this is good enough for now.

Upvotes: 2

Related Questions