我正在尝试模仿类似于您在 Photoshop 中看到的路径编辑,它以这种方式交互......
我遇到问题的地方是
这是我所拥有的:
这是我试图匹配的内容的参考:
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_()
您无法通过检查项目的选择更改来实现此目的,因为当按下鼠标时选择一个项目时,视图已经取消选择所有其他项目。
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)