在 QGraphicsPixmapItem 中打开上下文菜单时,如何删除此 QGraphicsLineItem?
How can I delete this QGraphicsLineItem when context menu is open in a QGraphicsPixmapItem?
我正在开发一个 GUI,除少数特殊情况外,您可以在其中连接节点。这个实现在大多数情况下工作得很好,但经过一些测试我发现,当我通过 QGraphicsLineItem 将一个 QGraphicsPixmapItem 与另一个连接时,用户在完成 link 之前打开上下文菜单,该行卡住了,而且无法删除。
到link两个元素的过程是先按下该元素,然后在移动线条的同时按住,当指针悬停在另一个元素上时松开。这是分别使用 mousePressEvent、mouseMoveEvent 和 mouseReleaseEvent 实现的。
此代码是示例:
#!/usr/bin/env python3
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
class Ellipse(QGraphicsEllipseItem):
def __init__(self, x, y):
super(Ellipse, self).__init__(x, y, 30, 30)
self.setBrush(QBrush(Qt.darkBlue))
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setZValue(100)
def contextMenuEvent(self, event):
menu = QMenu()
first_action = QAction("First action")
second_action = QAction("Second action")
menu.addAction(first_action)
menu.addAction(second_action)
action = menu.exec(event.screenPos())
class Link(QGraphicsLineItem):
def __init__(self, x, y):
super(Link, self).__init__(x, y, x, y)
self.pen_ = QPen()
self.pen_.setWidth(2)
self.pen_.setColor(Qt.red)
self.setPen(self.pen_)
def updateEndPoint(self, x2, y2):
line = self.line()
self.setLine(line.x1(), line.y1(), x2, y2)
class Scene(QGraphicsScene):
def __init__(self):
super(Scene, self).__init__()
self.link = None
self.link_original_node = None
self.addItem(Ellipse(200, 400))
self.addItem(Ellipse(400, 400))
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
item = self.itemAt(event.scenePos(), QTransform())
if item is not None:
self.link_original_node = item
offset = item.boundingRect().center()
self.link = Link(item.scenePos().x() + offset.x(), item.scenePos().y() + offset.y())
self.addItem(self.link)
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
if self.link is not None:
self.link.updateEndPoint(event.scenePos().x(), event.scenePos().y())
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
if self.link is not None:
item = self.itemAt(event.scenePos(), QTransform())
if isinstance(item, (Ellipse, Link)):
self.removeItem(self.link)
self.link_original_node = None
self.link = None
class MainWindow(QMainWindow):
def __init__(self):
super(QMainWindow, self).__init__()
self.scene = Scene()
self.canvas = QGraphicsView()
self.canvas.setScene(self.scene)
self.setCentralWidget(self.canvas)
self.setGeometry(500, 200, 1000, 600)
self.setContextMenuPolicy(Qt.NoContextMenu)
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec())
如何摆脱行before/after上下文菜单事件?我试图阻止他们,但我不知道如何。
假设菜单仅通过按下鼠标按钮触发,解决方案是也删除 mouseButtonPress
中任何现有的 link 项。
def mousePressEvent(self, event):
if self.link is not None:
self.removeItem(self.link)
self.link_original_node = None
self.link = None
# ...
请注意,对于非常小的项目,itemAt
并不总是可靠的,因为项目的 shape()
可能会稍微偏离映射的鼠标位置。由于 link 在任何情况下都会被删除,因此只需在 mouseReleaseEvent()
:
中执行相同的操作
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
if self.link is not None:
item = self.itemAt(event.scenePos(), QTransform())
if isinstance(item, Ellipse):
# do what you need with the linked ellipses
# note the indentation level
self.removeItem(self.link)
self.link_original_node = None
self.link = None
我正在开发一个 GUI,除少数特殊情况外,您可以在其中连接节点。这个实现在大多数情况下工作得很好,但经过一些测试我发现,当我通过 QGraphicsLineItem 将一个 QGraphicsPixmapItem 与另一个连接时,用户在完成 link 之前打开上下文菜单,该行卡住了,而且无法删除。
到link两个元素的过程是先按下该元素,然后在移动线条的同时按住,当指针悬停在另一个元素上时松开。这是分别使用 mousePressEvent、mouseMoveEvent 和 mouseReleaseEvent 实现的。
此代码是示例:
#!/usr/bin/env python3
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
class Ellipse(QGraphicsEllipseItem):
def __init__(self, x, y):
super(Ellipse, self).__init__(x, y, 30, 30)
self.setBrush(QBrush(Qt.darkBlue))
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setZValue(100)
def contextMenuEvent(self, event):
menu = QMenu()
first_action = QAction("First action")
second_action = QAction("Second action")
menu.addAction(first_action)
menu.addAction(second_action)
action = menu.exec(event.screenPos())
class Link(QGraphicsLineItem):
def __init__(self, x, y):
super(Link, self).__init__(x, y, x, y)
self.pen_ = QPen()
self.pen_.setWidth(2)
self.pen_.setColor(Qt.red)
self.setPen(self.pen_)
def updateEndPoint(self, x2, y2):
line = self.line()
self.setLine(line.x1(), line.y1(), x2, y2)
class Scene(QGraphicsScene):
def __init__(self):
super(Scene, self).__init__()
self.link = None
self.link_original_node = None
self.addItem(Ellipse(200, 400))
self.addItem(Ellipse(400, 400))
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
item = self.itemAt(event.scenePos(), QTransform())
if item is not None:
self.link_original_node = item
offset = item.boundingRect().center()
self.link = Link(item.scenePos().x() + offset.x(), item.scenePos().y() + offset.y())
self.addItem(self.link)
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
if self.link is not None:
self.link.updateEndPoint(event.scenePos().x(), event.scenePos().y())
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
if self.link is not None:
item = self.itemAt(event.scenePos(), QTransform())
if isinstance(item, (Ellipse, Link)):
self.removeItem(self.link)
self.link_original_node = None
self.link = None
class MainWindow(QMainWindow):
def __init__(self):
super(QMainWindow, self).__init__()
self.scene = Scene()
self.canvas = QGraphicsView()
self.canvas.setScene(self.scene)
self.setCentralWidget(self.canvas)
self.setGeometry(500, 200, 1000, 600)
self.setContextMenuPolicy(Qt.NoContextMenu)
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec())
如何摆脱行before/after上下文菜单事件?我试图阻止他们,但我不知道如何。
假设菜单仅通过按下鼠标按钮触发,解决方案是也删除 mouseButtonPress
中任何现有的 link 项。
def mousePressEvent(self, event):
if self.link is not None:
self.removeItem(self.link)
self.link_original_node = None
self.link = None
# ...
请注意,对于非常小的项目,itemAt
并不总是可靠的,因为项目的 shape()
可能会稍微偏离映射的鼠标位置。由于 link 在任何情况下都会被删除,因此只需在 mouseReleaseEvent()
:
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
if self.link is not None:
item = self.itemAt(event.scenePos(), QTransform())
if isinstance(item, Ellipse):
# do what you need with the linked ellipses
# note the indentation level
self.removeItem(self.link)
self.link_original_node = None
self.link = None