Вам следует больше использовать систему «сигнал / слот»: кнопка должна уведомить представление о том, что она хочет подключиться, и уведомить, когда она движется. Линия должна обрабатывать свои обновления, когда кнопка перемещается.
Это означает, что линия связана с кнопкой, а кнопка с видом.
Быстрый пример:
Кнопка отправит сигнал connectionRequested
, когда вы хотите подключить его, и moved
, когда он движется.
class DragButton(QtWidgets.QPushButton):
connectionRequested = pyqtSignal(QtWidgets.QPushButton)
moved = pyqtSignal()
def __init__(self, title, parent=None):
super().__init__(title, parent)
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.showMenu)
def showMenu(self):
menu = QtWidgets.QMenu()
menu.addAction("connect", lambda: self.connectionRequested.emit(self))
menu.exec_(self.cursor().pos())
def mouseMoveEvent(self, e):
if e.buttons() != QtCore.Qt.LeftButton:
return
mimeData = QtCore.QMimeData()
drag = QtGui.QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.exec_(QtCore.Qt.MoveAction)
self.moved.emit()
Линия имеет два параметра: source
и destination
, которые используются для рисования линии между их позициями (вы можете определить другой метод, чем pos
, чтобы вернуть относительную позицию, такую как центр вашей кнопки).
class GraphicsLineItem(QtWidgets.QGraphicsLineItem):
def __init__(self, source, destination, parent=None):
super().__init__(parent)
self.source = source
self.destination = destination
self.move()
self.source.moved.connect(self.move)
self.destination.moved.connect(self.move)
def contextMenuEvent(self, event):
menu = QtWidgets.QMenu()
menu.addAction("Delete", self.remove)
menu.exec_(self.cursor().pos())
print(self.a)
def remove(self):
self.scene().removeItem(self)
def shape(self):
p = super(GraphicsLineItem, self).shape()
stroker = QtGui.QPainterPathStroker()
stroker.setWidth(20)
return stroker.createStroke(p)
def move(self):
self.setLine(QLineF(self.source.pos(), self.destination.pos()))
Представление создаст новую строку, когда вы нажмете на действие connect
второй кнопки.
class View(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(View, self).__init__(parent)
self.setScene(QtWidgets.QGraphicsScene(self))
self.setAcceptDrops(True)
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
self.btn1 = QtWidgets.QPushButton("Start")
self.btn1.setGeometry(230, 80, 100, 30)
self.btn1.setCheckable(True)
self.btn1.clicked.connect(self.add_Text)
self.source = None
def clearScene(self):
self.scene().clear()
self.source = None
def add_Text(self):
button = DragButton('Text', self)
button.setGeometry(230, 80, 100, 30)
button.show()
button.connectionRequested.connect(self.connectButton)
def connectButton(self, button):
# Do not connect a button with itself
if not self.source or button == self.source:
self.source = button
return
line = GraphicsLineItem(self.source, button)
self.scene().addItem(line)
self.source = None
def dragEnterEvent(self, e):
e.accept()
def dragMoveEvent(self, e):
e.accept()
def dropEvent(self, e):
btn = e.source()
position = e.pos()
btn.move(position)
e.setDropAction(QtCore.Qt.MoveAction)
e.accept()