目标
按住鼠标左键和crtl键进入切割模式,edge在被切割的路径上就会被切除
实现
定义一个新模式,切割模式
MODE_EDGE_CUT = 3
按下鼠标左键
由于需要按下鼠标左键和crtl,那么这个这个模式肯定是在view里的leftMouseButtonPress(self, event) 里判断并执行 则在leftMouseButtonPress(self, event) 新增代码
if item is None:
if event.modifiers() & Qt.ControlModifier:
self.mode = MODE_EDGE_CUT
fakeEvent = QMouseEvent(QEvent.MouseButtonRelease,event.localPos(),event.screenPos(),
Qt.LeftButton,Qt.NoButton,event.modifiers())
super().mouseReleaseEvent(fakeEvent)
QApplication.setOverrideCursor(Qt.CrossCursor)
return
因为点击是空白处,所以判断item是否为None 之后建立一个鼠标左键松开的假事件,并且将鼠标指针变为十字形
至于为什么要建立这个假事件,我也不太清楚,可能是为了以防冲突吧
最后return
绘制切割线
建立文件node_graphics_cutline.py
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class QDMCutLine(QGraphicsItem):
def __init__(self, parent=None):
super().__init__(parent)
self.line_points = []
self._pen = QPen(Qt.white)
self._pen.setWidth(2.0)
self._pen.setDashPattern([3, 3])
self.setZValue(2)
def boundingRect(self):
return QRectF(0, 0, 1, 1)
def paint(self, painter, QStyleOptionGraphicsItem, widget=None):
painter.setRenderHint(QPainter.Antialiasing)
painter.setBrush(Qt.NoBrush)
painter.setPen(self._pen)
poly = QPolygonF(self.line_points)
painter.drawPolyline(poly)
其中self.line_points = [] 用于存储绘制折线的点 而
poly = QPolygonF(self.line_points)
painter.drawPolyline(poly)
用于绘制折线 接着在node_graphics_view.py 里使用命令from node_graphics_cutline import QDMCutLine 导入 再进行建立一个对象
self.cutline = QDMCutLine()
self.grScene.addItem(self.cutline)
此时这个对象里的line_points 还是一个空列表,为了绘制折线需要为里面添加点
鼠标移动
按下去之后,接着就是移动 那么需要让mouseMoveEvent(self, event) 在切割模式下执行新的命令
if self.mode == MODE_EDGE_CUT:
pos = self.mapToScene(event.pos())
self.cutline.line_points.append(pos)
self.cutline.update()
切除方法
还是在node_graphics_view.py 定义一个方法用于切除edge
def cutIntersectingEdge(self):
for ix in range(len(self.cutline.line_points)-1):
p1 = self.cutline.line_points[ix]
p2 = self.cutline.line_points[ix + 1]
for edge in self.grScene.scene.edges:
if edge.grEdge.intersectsWith(p1, p2):
edge.remove()
首先对折线中每条直线进行遍历 如果这条直线与edge有相交,则删除此edge 因此,我们需要在edge里定义方法intersectsWith 来判断是否相交 在QT中提供了QPainterPath.intersects(path) 的方法来判断两个path是否相交 所以我们需要在node_graphics_edge.py 获取path 因此,需要使直线和贝塞尔曲线返回path(此处只显示return的代码)
class QDMGraphicsEdgeDirect(QDMGraphicsEdge):
def updatePath(self):
return path
class QDMGraphicsEdgeBezier(QDMGraphicsEdge):
def updatePath(self):
return path
由于updatePath(self) 返回的是path,所以在paint方法中也需要修改(修改了一行代码)
def paint(self, painter, QStyleOptionGraphicsItem, widge=None):
self.setPath(self.updatePath())
接着就可以定义intersectsWith 方法了
def intersectsWith(self,p1,p2):
cutpath = QPainterPath(p1)
cutpath.lineTo(p2)
path = self.updatePath()
return cutpath.intersects(path)
最后通过cutpath.intersects(path) 来判断两个路径是否相交来返回True 或者 False,使得
if edge.grEdge.intersectsWith(p1, p2):
edge.remove()
是否删除edge
鼠标左键松开
在node_graphics_view.py 里的leftMouseButtonRelease 里定义新命令
if self.mode == MODE_EDGE_CUT:
self.cutIntersectingEdge()
self.cutline.line_points = []
self.cutline.update()
QApplication.setOverrideCursor(Qt.ArrowCursor)
self.mode = MODE_NOOP
来执行上述的切除方法 切除结束后清空所有点 再将鼠标指针变为箭头 将模式变为正常模式
|