The problem is the following - online line is created. Left mouse button - add point, right button - finish line creation. Adding points passes without errors, but when you press the right button - the application window simply closes, without any errors and warnings.
I give an example, to the maximum deleted unnecessary.
Debugging comes to line 93 (node.change_position_signal.connect (self.update_point_positions)) and everything silently closes.
Usually I manage to solve the problem myself, but here I am already in despair, I have already spent three days on this problem.
from PyQt5.QtWidgets import (QGraphicsPathItem, QGraphicsObject, QApplication, QGraphicsView, QGraphicsScene, QGraphicsItem) from PyQt5.QtCore import Qt, pyqtSignal, QMarginsF, QRectF, QPointF, pyqtSlot from PyQt5.QtGui import (QPainter, QPainterPath, QPainterPathStroker, QColor, QPen, QBrush) class MVGraphicsLinkTest(QGraphicsPathItem, QGraphicsObject): def __init__(self, scene): super().__init__() scene.addItem(self) self.setFlag(QGraphicsItem.ItemIsFocusable, True) self.setAcceptHoverEvents(True) # lines width self._width = 10 self._color = QColor(0, 100, 0, 255) self._brush = QBrush(self._color) self.setBrush(self._brush) self.setPen(QPen(Qt.NoPen)) # stroker self._path_stroker = QPainterPathStroker() self._path_stroker.setWidth(self._width) self._path_stroker.setCapStyle(Qt.RoundCap) self._path_stroker.setJoinStyle(Qt.RoundJoin) self._path_stroker.setDashPattern(Qt.SolidLine) # init first point self.nodes = [MVGraphicsLinkNode(QPointF(10,10))] self.points = [QPointF(10,10)] # init dummy point self._dummy_mode = True self._dummy_node = MVGraphicsLinkNode(QPointF(10,10), parent=self) self._dummy_point = QPointF(10,10) self.update_path() self.grabMouse() def color(self): return self._color def update_path(self): self.prepareGeometryChange() for i, point in enumerate(self.points): if i==0: self._path = QPainterPath(point) else: self._path.lineTo(point) if self._dummy_mode: self._path.lineTo(self._dummy_point) self.setPath(self._path_stroker.createStroke(self._path)) def mousePressEvent(self, e): if e.button() == Qt.LeftButton: # builds line if self._dummy_mode: self.points.append(e.pos()) self.nodes.append(self._dummy_node) self._dummy_node = MVGraphicsLinkNode(e.pos(), parent=self) if e.button() == Qt.RightButton: # exit dummy mode and saving points if self._dummy_mode: self._dummy_mode = False self._dummy_point = None self.scene().removeItem(self._dummy_node) self._dummy_node = None self.connect_nodes() self.update_path() self.ungrabMouse() if len(self.points)<2: self.delete_self() super().mousePressEvent(e) e.accept() def mouseMoveEvent(self, e): if self._dummy_mode: self._dummy_point = e.pos() self._dummy_node.setPos(self._dummy_point) self.update_path() super().mouseMoveEvent(e) def connect_nodes(self): # connecting node signals for i, node in enumerate(self.nodes): node.set_index(i) ############################################################### # CRUSH ON THIS LINE ########################################## ############################################################### node.change_position_signal.connect(self.update_point_positions) node.delete_signal.connect(self.delete_node) def disconnect_nodes(self): # disconnecting node signals for node in self.nodes: node.change_position_signal.disconnect() node.delete_signal.disconnect() def delete_node(self, index): if len(self.points)>2: self.disconnect_nodes() self.points.pop(index) del_node = self.nodes.pop(index) self.scene().removeItem(del_node) self.connect_nodes() self.update_path() print('scene items: {0}'.format(len(self.scene().items()))) @pyqtSlot() def update_point_positions(self): for i, node in enumerate(self.nodes): self.points[i] = node.scenePos() self.update_path() class MVGraphicsLinkNode(QGraphicsObject): change_position_signal = pyqtSignal() delete_signal = pyqtSignal(int) def __init__(self, pos, movable=True, parent=None): super().__init__(parent=parent) self.setPos(pos) self._movable = movable self._index = -1 self.setFlag(QGraphicsItem.ItemIsMovable, self._movable) self.setFlag(QGraphicsItem.ItemIsSelectable, self._movable) self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, True) self.setAcceptHoverEvents(True) self.setEnabled(self._movable) self._hover = False self._size = 12 self._color = QColor(200, 200, 50, 200) if parent: self._color = parent.color() self._color_sel = QColor(self._color) self._color_sel.setAlpha(100) self._brush1 = QBrush(self._color_sel) self._brush2 = QBrush(self._color) self._pen = QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine) def set_index(self, index): self._index = index self.setToolTip('index = {0}'.format(self._index)) def itemChange(self, change, value): if change == QGraphicsItem.ItemScenePositionHasChanged and self.scene(): self.change_position_signal.emit() return super().itemChange(change, value) def size(self): if self._hover: return 2*self._size else: return self._size def boundingRect(self): return QRectF(-self._size, -self._size, 2*self._size, 2*self._size) def shape(self): path = QPainterPath() path.addEllipse(QPointF(), self.size()/2, self.size()/2) return path def paint(self, painter, option, widget=None): painter.setBrush(self._brush1) painter.setPen(self._pen) if self._hover or self.isSelected(): painter.drawEllipse(QPointF(), self._size, self._size) painter.setBrush(self._brush2) painter.drawEllipse(QPointF(), self._size/2, self._size/2) def hoverEnterEvent(self, e): self._hover = self._movable super().hoverLeaveEvent(e) def hoverLeaveEvent(self, e): self._hover = False super().hoverLeaveEvent(e) def mouseDoubleClickEvent(self, e): print('delete sender: {0}'.format(self._index)) self.delete_signal.emit(self._index) super().mouseDoubleClickEvent(e) if __name__ == '__main__': import sys app = QApplication(sys.argv) view = QGraphicsView() view.setDragMode(QGraphicsView.RubberBandDrag) scene = QGraphicsScene() m = QMarginsF(30, 30, 30, 30) scene_rect = QRectF(0, 0, 600, 600) scene.setSceneRect(scene_rect.marginsAdded(m)) view.setScene(scene) view.setRenderHint(QPainter.Antialiasing) view.fitInView(scene.sceneRect(), Qt.KeepAspectRatio) MVGraphicsLinkTest(scene) view.show() sys.exit(app.exec_()) 
