在QGraphicsScene选择更改后切换所选项目的QPen

时间:2017-12-06 13:59:22

标签: python selection pyside qgraphicsview qgraphicsscene

如何切换所选图形视图项目的QPen颜色?理想情况下,我想在图形视图或图形场景对象中处理这种颜色变化,而不是在主窗口选择事件中直接处理它。

感谢任何帮助。目前,当选择对象时,它会将笔颜色变为白色。我不确定如何将其关闭以避免遍历所有对象。

有没有办法可以在MyGraphicsView类中添加一个函数来处理图形中任何和所有选定项目的笔的颜色变化?

更新:更详细的信息 以下列出了我试图解决的选择问题:

  1. 当用户点击并制作选择矩形时,应取消选择所有项目,将其恢复为默认的笔颜色。新选择的项目应具有白色笔颜色。如果用户持有控件,则应添加新选择的项目。如果已经选择了项目并且矩形越过它们,它仍应保持选中状态。
  2. 如果用户点击光标下没有项目的负区域,则应清除当前选择。
  3. 如果用户点击某个项目,则应选择该项目,并将笔颜色设为白色。
  4. 如果用户持有控件,则应始终添加到选择中。
  5. enter image description here

    enter image description here

    代码

    import sys
    from PySide.QtGui import *
    from PySide.QtCore import *
    import random
    
    
    class MyGraphicsView(QGraphicsView):
        def __init__(self):
            super(MyGraphicsView, self).__init__()
            self.setDragMode(QGraphicsView.RubberBandDrag)
            self._isPanning = False
            self._mousePressed = False
            # self.setBackgroundBrush(QImage("C:/Users/jmartini/Desktop/Temp/images/flag_0140.jpg"))
            self.setCacheMode(QGraphicsView.CacheBackground)
            self.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff )
            self.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff )
    
    
        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__()
            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.gv.setScene(MyGraphicsScene(self))
            self.setCentralWidget(self.gv)
    
            self.gv.scene().selectionChanged.connect(self.selection_changed)
            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 = scene.addEllipse(x, y, r, r, QPen(QColor(255,128,0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin), QBrush(QColor(255,128,20,128)))
                rect.setFlag( QGraphicsItem.ItemIsSelectable )
                rect.setFlag( QGraphicsItem.ItemIsMovable )
    
            rect = scene.addEllipse(300, 500, 20, 20, QPen(QColor(255,128,0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin), QBrush(QColor(255,0,0,128)))
            rect.setFlag( QGraphicsItem.ItemIsSelectable )
            rect.setFlag( QGraphicsItem.ItemIsMovable )
    
    
        def selection_changed(self):
            selection = self.gv.scene().selectedItems()
            print 'Selected:', len(selection)
            for i in selection:
                i.setPen(QPen(QColor(255,255,255), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
    
    
    def main():
        app = QApplication(sys.argv)
        ex = MyMainWindow()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == '__main__':
        main()
    

1 个答案:

答案 0 :(得分:1)

应该可以通过缓存最后一个选择然后在进行新选择之前清除它来获得所需的行为:

class MyGraphicsView(QGraphicsView):
    def __init__(self):
        ...
        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

这是完整的脚本:

import sys
from PySide.QtGui import *
from PySide.QtCore import *
import random


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__()
        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 = scene.addEllipse(x, y, r, r, QPen(QColor(255,128,0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin), QBrush(QColor(255,128,20,128)))
            rect.setFlag( QGraphicsItem.ItemIsSelectable )
            rect.setFlag( QGraphicsItem.ItemIsMovable )

        rect = scene.addEllipse(300, 500, 20, 20, QPen(QColor(255,128,0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin), QBrush(QColor(255,0,0,128)))
        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()