“如何在两个按钮之间创建一个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_())
最佳答案
您应该更多地使用信号/槽系统:按钮应该通知 View 它想要连接并在它移动时发出通知。当按钮移动时,该线应该自行处理更新。
这意味着线连接到按钮,按钮连接到 View 。
一个简单的例子:
当您想要连接按钮时,按钮将发送信号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()))
当您单击第二个按钮的“连接”操作时, View 将创建一个新行。
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()
关于python - PyQt : How to create a lineItem between two button and can move with button?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56206236/