QGraphicsItem 仅在选择父项时可见

问题描述 投票:0回答:1

我正在尝试模仿类似于您在 Photoshop 中看到的路径编辑,它以这种方式交互......

  1. 您选择路径,它的点变得可见
  2. 用户可以点击并拖动Path的任意Point项,来调整Path
  3. 当用户直接单击并拖动路径时,它会移动路径
  4. 取消选择路径后,点将再次隐藏

我遇到问题的地方是

  1. 取消选择路径时隐藏点,但编辑所选样条线的点时不隐藏

这是我所拥有的:

这是我试图匹配的内容的参考:

import sys
import math
import random

from PySide2 import QtWidgets, QtGui, QtCore

# SETTINGS
handle_size = 16
handle_color = QtGui.QColor(40,130,230)
handle_radius = 8


class AnnotationPointItem(QtWidgets.QGraphicsEllipseItem):
    def __init__(self, positionFlag=0, pos=QtCore.QPointF(), parent=None):
        super(AnnotationPointItem, self).__init__(-handle_radius, -handle_radius, 2*handle_radius, 2*handle_radius, parent)
        
        self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemIsSelectable | QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges)    
        self.setPen(QtGui.QPen(handle_color, 4, QtCore.Qt.SolidLine))
        self.setBrush(QtGui.QBrush(QtGui.QColor('white')))
        self.positionFlag = positionFlag 


    def paint(self, painter, option, widget=None):
        # Remove the selection outline
        # if self.isSelected():
        #     option.state &= ~QtWidgets.QStyle.State_Selected

        super(AnnotationPointItem, self).paint(painter, option, widget)


    # def mousePressEvent(self, event):
    #     # Handle the event, but don't propagate to the parent
    #     # event.accept()
    #     print('clicked....')
    #     return super(AnnotationPointItem, self).mousePressEvent(event)


    def itemChange(self, change, value):
        # print(change, self.isSelected())
        if change == QtWidgets.QGraphicsItem.ItemPositionChange:
            # print('ItemPositionChange')
            pass
        elif change == QtWidgets.QGraphicsItem.ItemPositionHasChanged:
            # print('ItemPositionHasChanged')
            parent = self.parentItem()
            if parent:
                # Get the position of the cursor in the view's coordinates
                if self.positionFlag == 0:
                    parent.setPoints(start=self.pos())
                elif self.positionFlag == 1:
                    parent.setPoints(end=self.pos())
        elif change == QtWidgets.QGraphicsItem.ItemSelectedChange:
            pass
        return super(AnnotationPointItem, self).itemChange(change, value)


class AnnotationPathItem(QtWidgets.QGraphicsLineItem):
    def __init__(self, 
        start=QtCore.QPointF(), 
        end=QtCore.QPointF(), 
        color=QtCore.Qt.green,
        thickness=10,
        parent=None):
        super(AnnotationPathItem, self).__init__(start.x(), start.y(), end.x(), end.y(), parent)

        self._color = color
        self._thickness = thickness

        self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemIsSelectable)
        self.setPen(QtGui.QPen(self._color, self._thickness, QtCore.Qt.SolidLine))

        # child items
        self.startPointItem = AnnotationPointItem(positionFlag=0, parent=self)
        self.startPointItem.hide()
        self.startPointItem.setPos(self.line().p1())

        self.endPointItem = AnnotationPointItem(positionFlag=1, parent=self)
        self.endPointItem.hide()
        self.endPointItem.setPos(self.line().p2())


    def itemChange(self, change, value):
        if change == QtWidgets.QGraphicsItem.ItemSelectedChange:
            self.selectionChanged(value)
        return super(AnnotationPathItem, self).itemChange(change, value)


    def selectionChanged(self, selected):
        # Implement what you want to do when the selection changes
        print(self.startPointItem.isSelected(), self.endPointItem.isSelected())
        if selected or self.startPointItem.isSelected() or self.endPointItem.isSelected():
            self.startPointItem.show()
            self.endPointItem.show()
        # else:
        #     self.startPointItem.hide()
        #     self.endPointItem.hide()


    def paint(self, painter, option, widget=None):
        # Remove the selection outline
        if self.isSelected():
            option.state &= ~QtWidgets.QStyle.State_Selected

        super(AnnotationPathItem, self).paint(painter, option, widget)


    def setPoints(self, start=None, end=None):
        currentLine = self.line()
        if start != None:
            currentLine.setP1(start)
        if end != None:
            currentLine.setP2(end)
        self.setLine(currentLine)


class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.resize(1200,1200)

        self.scene = QtWidgets.QGraphicsScene(self)
        self.scene.setBackgroundBrush(QtGui.QColor(40,40,40))

        self.view = QtWidgets.QGraphicsView(self)
        self.view.setSceneRect(-4000, -4000, 8000, 8000)
        self.view.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform)
        self.view.setMouseTracking(True)
        self.view.setScene(self.scene)

        self.addButton = QtWidgets.QPushButton("Add Annotation", self)
        self.addButton.clicked.connect(self.add_annotation)

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.view)
        layout.addWidget(self.addButton)
        self.setLayout(layout)

        # samples
        item = AnnotationPathItem(QtCore.QPointF(-70, -150), QtCore.QPointF(150, -350))
        self.scene.addItem(item)


    def add_annotation(self):
        r = random.randint(0,255)
        g = random.randint(0,255)
        b = random.randint(0,255)
        color = QtGui.QColor(r,g,b)
        startPos = QtCore.QPointF(random.randint(-200,200), random.randint(-200,200))
        endPos = QtCore.QPointF(random.randint(-200,200), random.randint(-200,200))
        item = AnnotationPathItem(startPos, endPos, color)
        self.scene.addItem(item)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()
python pyside2 qgraphicsitem
1个回答
0
投票

您无法通过检查项目的选择更改来实现此目的,因为当按下鼠标时选择一个项目时,视图已经取消选择所有其他项目。

相反,您可以使用场景的

selectionChanged
信号(该信号在所有选择更改完成时发出),并决定是否显示项目。由于项目通常不是首先使用场景创建的,因此您必须在
ItemSceneChange
项目更改时连接到信号:

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSceneChange:
            if self.scene():
                self.scene().selectionChanged.disconnect(
                    self.updateChildSelection)
            if value:
                value.selectionChanged.connect(self.updateChildSelection)
        return super(AnnotationPathItem, self).itemChange(change, value)

    def updateChildSelection(self):
        selection = set(self.scene().selectedItems())
        showItems = bool(
            set((self, self.startPointItem, self.endPointItem)) & selection
        )
        self.startPointItem.setVisible(showItems)
        self.endPointItem.setVisible(showItems)
© www.soinside.com 2019 - 2024. All rights reserved.