Removing dotted rectangle on selected item

前端 未结 1 1510
暖寄归人
暖寄归人 2021-01-16 11:39

I have been trying to learn a bit more about the QGraphicsView widget by taking a look at this example here:

Toggle QPen for selected items after QGraphicsScene sele

相关标签:
1条回答
  • 2021-01-16 12:04

    If you want to remove the rectangle from the selection of the item in python you must use the following:

    class GraphicsEllipseItem(QGraphicsEllipseItem):
        def paint(self, painter, option, widget):
            option.state &= ~QStyle.State_Selected
            super(GraphicsEllipseItem, self).paint(painter, option, widget)
    

    Complete script

    import sys
    from PyQt4.QtGui import *
    from PyQt4.QtCore import *
    import random
    
    
    class GraphicsEllipseItem(QGraphicsEllipseItem):
        def paint(self, painter, option, widget):
            option.state &= ~QStyle.State_Selected
            super(GraphicsEllipseItem, self).paint(painter, option, widget)
    
    
    class MyGraphicsView(QGraphicsView):
        def __init__(self):
            super(MyGraphicsView, self).__init__()
            self.setDragMode(QGraphicsView.RubberBandDrag)
            self._isPanning = False
            self._mousePressed = False
            self.setCacheMode(QGraphicsView.CacheBackground)
            self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.setScene(MyGraphicsScene(self))
            self.scene().selectionChanged.connect(self.selection_changed)
            self._current_selection = []
    
        def select_items(self, items, on):
            pen = QPen(
                QColor(255, 255, 255) if on else QColor(255, 128, 0),
                0.5,
                Qt.SolidLine,
                Qt.RoundCap,
                Qt.RoundJoin,
            )
            for item in items:
                item.setPen(pen)
    
        def selection_changed(self):
            try:
                self.select_items(self._current_selection, False)
                self._current_selection = self.scene().selectedItems()
                self.select_items(self._current_selection, True)
            except RuntimeError:
                pass
    
        def mousePressEvent(self, event):
            if event.button() == Qt.LeftButton:
                self._mousePressed = True
                if self._isPanning:
                    self.setCursor(Qt.ClosedHandCursor)
                    self._dragPos = event.pos()
                    event.accept()
                else:
                    super(MyGraphicsView, self).mousePressEvent(event)
            elif event.button() == Qt.MiddleButton:
                self._mousePressed = True
                self._isPanning = True
                self.setCursor(Qt.ClosedHandCursor)
                self._dragPos = event.pos()
                event.accept()
    
        def mouseMoveEvent(self, event):
            if self._mousePressed and self._isPanning:
                newPos = event.pos()
                diff = newPos - self._dragPos
                self._dragPos = newPos
                self.horizontalScrollBar().setValue(
                    self.horizontalScrollBar().value() - diff.x()
                )
                self.verticalScrollBar().setValue(
                    self.verticalScrollBar().value() - diff.y()
                )
                event.accept()
            else:
                super(MyGraphicsView, self).mouseMoveEvent(event)
    
        def mouseReleaseEvent(self, event):
            if event.button() == Qt.LeftButton:
                if self._isPanning:
                    self.setCursor(Qt.OpenHandCursor)
                else:
                    self._isPanning = False
                    self.setCursor(Qt.ArrowCursor)
                self._mousePressed = False
            elif event.button() == Qt.MiddleButton:
                self._isPanning = False
                self.setCursor(Qt.ArrowCursor)
                self._mousePressed = False
            super(MyGraphicsView, self).mouseReleaseEvent(event)
    
        def mouseDoubleClickEvent(self, event):
            self.fitInView(self.sceneRect(), Qt.KeepAspectRatio)
            pass
    
        def keyPressEvent(self, event):
            if event.key() == Qt.Key_Space and not self._mousePressed:
                self._isPanning = True
                self.setCursor(Qt.OpenHandCursor)
            else:
                super(MyGraphicsView, self).keyPressEvent(event)
    
        def keyReleaseEvent(self, event):
            if event.key() == Qt.Key_Space:
                if not self._mousePressed:
                    self._isPanning = False
                    self.setCursor(Qt.ArrowCursor)
            else:
                super(MyGraphicsView, self).keyPressEvent(event)
    
        def wheelEvent(self, event):
            # zoom factor
            factor = 1.25
    
            # Set Anchors
            self.setTransformationAnchor(QGraphicsView.NoAnchor)
            self.setResizeAnchor(QGraphicsView.NoAnchor)
    
            # Save the scene pos
            oldPos = self.mapToScene(event.pos())
    
            # Zoom
            if event.delta() < 0:
                factor = 1.0 / factor
            self.scale(factor, factor)
    
            # Get the new position
            newPos = self.mapToScene(event.pos())
    
            # Move scene to old position
            delta = newPos - oldPos
            self.translate(delta.x(), delta.y())
    
    
    class MyGraphicsScene(QGraphicsScene):
        def __init__(self, parent):
            super(MyGraphicsScene, self).__init__(parent)
            self.setBackgroundBrush(QBrush(QColor(50, 50, 50)))
            # self.setSceneRect(50,50,0,0)
    
    
    class MyMainWindow(QMainWindow):
        def __init__(self):
            super(MyMainWindow, self).__init__()
            self.setWindowTitle("Test")
            self.resize(800, 600)
            self.gv = MyGraphicsView()
            self.setCentralWidget(self.gv)
            self.populate()
    
        def populate(self):
            scene = self.gv.scene()
            for i in range(500):
                x = random.randint(0, 1000)
                y = random.randint(0, 1000)
                r = random.randint(2, 8)
                rect = GraphicsEllipseItem(x, y, r, r)
                rect.setPen(
                    QPen(QColor(255, 128, 0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
                )
                rect.setBrush(QBrush(QColor(255, 128, 20, 128)))
                scene.addItem(rect)
                rect.setFlag(QGraphicsItem.ItemIsSelectable)
                rect.setFlag(QGraphicsItem.ItemIsMovable)
    
            rect = GraphicsEllipseItem(300, 500, 20, 20)
            rect.setPen(
                QPen(QColor(255, 128, 0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
            )
            rect.setBrush(QBrush(QColor(255, 0, 0, 128)))
            scene.addItem(rect)
            rect.setFlag(QGraphicsItem.ItemIsSelectable)
            rect.setFlag(QGraphicsItem.ItemIsMovable)
    
    
    def main():
        app = QApplication(sys.argv)
        ex = MyMainWindow()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    Explanation of option.state &= ~QStyle.State_Selected:

    state is an attribute of QStyleOptionGraphicsItem that stores the information of the state of the painting that may contain a combination of the following flags:

    In this case the flags can be combined with using the "|" operator, and deactivate using the "&~".

    To understand it better, let's use the following example: we set the state in State_Active and State_Editing as initial state:

    state = State_Active | State_Editing
          = 0x00010000 | 0x00400000
          = 0x00410000
    

    And to deactivate the State_Active flag:

    state & ~State_Active
    0x00410000 & ~(0x00010000)
    0x00410000 &   0xFFFEFFFF
    0x00400000
    

    As you can see, flag State_Active is removed without removing other flags only with binary operations.

    So how do you want to deactivate the State_Selected flag and replace it to the state then it must be done:

    option.state = option.state & ~QStyle.State_Selected
    option.state &= ~QStyle.State_Selected
    
    0 讨论(0)
提交回复
热议问题