1

I am developing an application using pyqt 4 so hopefully I am only making a rookie mistake.

I found I cannot move a QGraphicsItems and QGraphicsItemGroups in a scene once I use custom event handlers for mousePressEvent() and mouseMoveEvent().

My application permits me to draw arbitrary shapes however I press CTRL key modifier to set my event handlers so that I can select objects (and add them to QGraphicsItemGroup) to move all selected objects.

from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Window(QtGui.QWidget):
def __init__(self):
    QtGui.QWidget.__init__(self)
    self.view = View(self)
    layout = QtGui.QVBoxLayout(self)
    layout.addWidget(self.view)
    self.setMouseTracking(True)
def __init__(self, parent):
    QtGui.QGraphicsView.__init__(self, parent)
    self.activeScene=QtGui.QGraphicsScene(self)
    self.setScene(self.activeScene)
    self.setInteractive(True)
    self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
    self.startpos = None
    self.endpos = None
    self.multiSegmentLine = QtGui.QGraphicsItemGroup(scene=self.activeScene)   
    self.multiSegmentLine.setFlags(QtGui.QGraphicsItemGroup.ItemIsSelectable)
    self.linePen=QPen(Qt.green, 3, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)        
    self.linesegment=QtGui.QGraphicsLineItem

# Create a group of selected items to move as a group        
    self.createMoveGroup = QtGui.QGraphicsItemGroup(scene=self.activeScene)
    self.createMoveGroup.setFlags(QtGui.QGraphicsItemGroup.ItemIsMovable)
    # TESTING
    self.boxxy = self.activeScene.addRect(10,10,100,100,self.linePen)
    self.boxxy.setFlags(QtGui.QGraphicsItem.ItemIsMovable)

# Booleans for state machine 
    self.stateNewLine=True     # Flag to determine line state True = new line, False = continuation of multisegment line
    self.stateSelectItems=False # Flag to help determine True = item selection mode enabled, False = line drawing mode enabled

# Create event handler
def mousePressEvent(self, event):        
    if event.button()==QtCore.Qt.LeftButton:  
        # If CTRL key is not pressed then self.stateSelectItems is FALSE and 
        # mouse handling is normal
        if self.stateSelectItems == False:
            # New line has been started so no end point has been determined
            if self.stateNewLine == True:        
            # Record starting position if creating a new line.  This is used as 
            # origin for line drawn from start position to mouse tip.
                self.startpos = QtCore.QPointF(self.mapToScene(event.pos())) 

            # The line is not new but rather is a multiple segment line.
            elif self.stateNewLine == False:
                # Update the length of the run            
                UserLineList.updateRunLength(self.linesegment.line())
                self.startpos = self.endpos             # Start new line at endpoint of previous segment
                self.segmentCount = self.segmentCount+1     # increment segment count
                #self.multiSegmentLine.setFlag(QtGui.QGraphicsItem.ItemIsMovable)
                # Add line from starting position to location of mouse click   
                #self.linesegment=self.scene().addLine(QtCore.QLineF(self.startpos,self.endpos))  
                self.linesegment = self.activeScene.addLine(QtCore.QLineF(self.startpos,self.endpos))                  
                self.linesegment.setPen(self.linePen)
                # Add newly created line to item group
                self.multiSegmentLine.addToGroup(self.linesegment)
                self.activeScene.addItem(self.multiSegmentLine)
                self.activeScene.removeItem(self.linesegment)

        # If CTRL key is pressed thenself.stateSelectItems == True and mouse 
        # handling has to change to support moving one or more screen items
        elif self.stateSelectItems==True:
            print("ENTERED MOVEMENT MODE!")                
            currentItem=self.activeScene.itemAt(self.mapToScene(event.pos()))               
            if currentItem != None:
                self.createMoveGroup.addToGroup(currentItem)
                self.stateSelectItems = True  # set stateSelectItems flag to control mouse event handling

def mouseDoubleClickEvent(self,event):
#def mouseReleaseEvent(self, event):
    if event.button() == QtCore.Qt.LeftButton:   
        self.startpos=None 
        self.stateNewLine=True # multisegment line has ended
        # Create a record of the multisegment line
        UserLineList.addMultiSegmentLine(self.multiSegmentLine)

def mouseMoveEvent(self,event):  
    # If CTRL key is not pressed then self.stateSelectItems is FALSE and 
    # mouse handling is normal
    if self.stateSelectItems == False:
        # If this is a new line use start position at click
        if self.stateNewLine == True:
            self.endpos = QtCore.QPointF(self.mapToScene(event.pos()))          
            self.linesegment = self.activeScene.addLine(QtCore.QLineF(self.startpos,self.endpos))                        
            self.linesegment.setPen(self.linePen)
            self.stateNewLine = False                                
        # If this line builds upon an existing segment
        elif self.stateNewLine == False:
            self.endpos = QtCore.QPointF(self.mapToScene(event.pos()))          
            self.scene().removeItem(self.linesegment)            
            self.linesegment = self.activeScene.addLine(QtCore.QLineF(self.startpos,self.endpos))            
            self.linesegment.setPen(self.linePen)

    # If CTRL key is pressed thenself.stateSelectItems == True and mouse 
    # handling has to change to support moving one or more screen items        
    elif self.stateSelectItems == True:
        self.createMoveGroup.mouseMoveEvent(self, event)

def keyPressEvent(self,event):
    keyModifier = QtGui.QApplication.keyboardModifiers() #Listen for keyboard modifier keys
    if keyModifier == QtCore.Qt.ControlModifier:
        print("keyEvent Control Key is pressed")
        self.stateSelectItems=True

def keyReleaseEvent(self,event):       
    keyModifier = QtGui.QApplication.keyboardModifiers() #Listen for keyboard modifier keys
    if keyModifier == QtCore.Qt.ControlModifier:
        self.stateSelectItems=False
        self.createMoveGroup.ungrabMouse() # Selected items lose mouse grab
        self.activeScene.destroyItemGroup(self.createMoveGroup) # Remove all selected items from move group

if __name__ == '__main__':
      import sys
      app = QtGui.QApplication(sys.argv)   
      window = Window()
      window.resize(640, 480)
      window.show()
      sys.exit(app.exec_())

1 Answers1

0

Like in the answer to this question, you might want to do a call to the base-class in order to keep the existing event handling of the respective event. E.g. in the mouse press event handler you would add a line like:

def mousePressEvent(self, event):
    ...
    super(Window, self).mousePressEvent(event)
    ...

Do this in a similar way for all your custom event handlers.

Community
  • 1
  • 1
chiefenne
  • 565
  • 2
  • 15
  • 30