Python PyQt:如何在两个按钮之间创建一个lineItem,并可以使用按钮移动?

Python PyQt:如何在两个按钮之间创建一个lineItem,并可以使用按钮移动?,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,“如何在两个按钮之间创建一个lineItem并可以随按钮移动” 我的程序可以使用名为“添加按钮”的按钮创建新按钮 我想创建一个lineItem 当我单击创建的两个按钮名为“连接”的菜单操作时 现在,我可以在他们之间建立一条线。 但我还是希望他们在按钮移动时移动 我看到的一些例子是删除它并构建新行。。 但我只想移动线的位置 这条线能做这个动作吗? 下面是我的代码 import sys, os from PyQt5 import QtCore, QtGui, QtWidgets can_dra

“如何在两个按钮之间创建一个lineItem并可以随按钮移动”

我的程序可以使用名为“添加按钮”的按钮创建新按钮

我想创建一个lineItem 当我单击创建的两个按钮名为“连接”的菜单操作时

现在,我可以在他们之间建立一条线。 但我还是希望他们在按钮移动时移动

我看到的一些例子是删除它并构建新行。。 但我只想移动线的位置

这条线能做这个动作吗? 下面是我的代码

import sys, os
from PyQt5 import QtCore, QtGui, QtWidgets



can_draw=0
start=0
end=0
first_connect=0
second_connect =0


class DragButton(QtWidgets.QPushButton):
    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", self.connectLine)
        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)


    def connectLine(self):

        global can_draw
        global start
        global end
        global first_connect
        global second_connect 

        view = self.parent()

        can_draw +=1

        if can_draw == 1:


            start = QtCore.QPointF(view.mapToScene(self.pos()))


        if can_draw == 2:

            end = QtCore.QPointF(view.mapToScene(self.pos()))


            can_draw -= 2


            view.createLineItem(start,end)

class GraphicsLineItem(QtWidgets.QGraphicsLineItem):



    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)


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.line = None

    def _createLineF(self,start,end):

        return QtCore.QLineF(start, end)

    def createLineItem(self,start,end):

        self.line = GraphicsLineItem(self._createLineF(start,end))
        self.scene().addItem(self.line)


    def clearScene(self):
        self.scene().clear()
        self.line = None

    def add_Text(self):

        self.button = DragButton('Text', self)
        self.button.setGeometry(230, 80, 100, 30)

        self.button.show() 



    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)
        if self.line:
            self.line.setLine(self._createLineF())
        e.setDropAction(QtCore.Qt.MoveAction)
        e.accept()


class Window(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.view = View()
        self.button = QtWidgets.QPushButton(
            "Clear View", clicked=self.view.scene().clear
        )
        self.btn1 = QtWidgets.QPushButton("add button")
        self.btn1.setCheckable(True)
        self.btn1.clicked.connect(self.view.add_Text)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.view)
        layout.addWidget(self.btn1)


if __name__ == "__main__":

    import sys

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.resize(640, 480)
    window.show()
    sys.exit(app.exec_())

您应该更多地使用信号/插槽系统:按钮应该通知视图它想要连接,并在移动时通知视图。当按钮移动时,该行应自行处理其更新

这意味着线连接到按钮,按钮连接到视图

一个简单的例子:

当您想要连接时,按钮将发送信号
connectionrequest
,当按钮移动时,按钮将发送信号
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
以外的另一种方法来返回一个相对位置,如按钮的中心)

当您单击第二个按钮的
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()

您应该更多地使用信号/插槽系统:按钮应该通知视图它想要连接,并在移动时通知视图。当按钮移动时,该行应自行处理其更新

这意味着线连接到按钮,按钮连接到视图

一个简单的例子:

当您想要连接时,按钮将发送信号
connectionrequest
,当按钮移动时,按钮将发送信号
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
以外的另一种方法来返回一个相对位置,如按钮的中心)

当您单击第二个按钮的
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()