PyQt5中如何在QGraphicsPathItem鼠标悬停时显示文本?
实现QGraphicsPathItem悬停显示文本
问题说明
使用QGraphicsPathItem绘制连接线时,需要鼠标悬停在线条上时显示提示文本,目前hoverEnterEvent能正常触发,但不知道如何实现文本显示功能。
修改后的完整代码
import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * class NodeEditorWnd(QWidget): def __init__(self, parent=None): super().__init__(parent) self.initUI() def initUI(self): self.setGeometry(200, 200, 800, 600) self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) self.scene = MyScene() self.addNodes() self.view = MyView(self.scene) self.layout.addWidget(self.view) self.setWindowTitle("Node Editor") self.show() def addNodes(self): node1 = Node(self.scene, "My Awesome Node 1", inputs=[1,2,3], outputs=[1]) node2 = Node(self.scene, "My Awesome Node 2", inputs=[1,2,3], outputs=[1]) node1.setPos(-350, -250) node2.setPos(-75, 0) edge1 = Edge(self.scene, 100, 500, "这是连接线的提示文本") self.scene.addItem(edge1) class NodeContent(QWidget): def __init__(self, parent=None): super().__init__(parent) self.initUI() def initUI(self): self.layout = QVBoxLayout() self.layout.setContentsMargins(0,0,0,0) self.setLayout(self.layout) self.wdg_label = QLabel("Some Title") self.layout.addWidget(self.wdg_label) self.layout.addWidget(QTextEdit("foo")) class Node(QGraphicsItem): def __init__(self, scene_ref, title="MyNode", inputs=[], outputs=[], parent=None): super().__init__(parent) self.scene_ref = scene_ref self._title_color = Qt.white self._title_font = QFont("Ubuntu", 10) self.width = 180 self.height = 240 self.edge_size = 10.0 self.title_height = 24.0 self._padding = 4.0 self._pen_default = QPen(QColor("#7F000000")) self._pen_selected = QPen(QColor("#FFFFA637")) self._brush_title = QBrush(QColor("#FF313131")) self._brush_background = QBrush(QColor("#E3212121")) self.content = NodeContent() self.initTitle() self.title = title self.initContent() self.initUI() self.scene_ref.addNode(self) self.scene_ref.addItem(self) def boundingRect(self): return QRectF( 0, 0, 2 * self.edge_size + self.width, 2 * self.edge_size + self.height ).normalized() def initUI(self): self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFlag(QGraphicsItem.ItemIsMovable) def initTitle(self): self.title_item = QGraphicsTextItem(self) self.title_item.setDefaultTextColor(self._title_color) self.title_item.setFont(self._title_font) self.title_item.setPos(self._padding, 0) self.title_item.setTextWidth( self.width - 2 * self._padding ) @property def title(self): return self._title @title.setter def title(self, value): self._title = value self.title_item.setPlainText(self._title) def paint(self, painter, QStyleOptionGraphicsItem, widget=None): # 绘制标题栏 path_title = QPainterPath() path_title.setFillRule(Qt.WindingFill) path_title.addRoundedRect(0,0, self.width, self.title_height, self.edge_size, self.edge_size) path_title.addRect(0, self.title_height - self.edge_size, self.edge_size, self.edge_size) path_title.addRect(self.width - self.edge_size, self.title_height - self.edge_size, self.edge_size, self.edge_size) painter.setPen(Qt.NoPen) painter.setBrush(self._brush_title) painter.drawPath(path_title.simplified()) # 绘制内容区域 path_content = QPainterPath() path_content.setFillRule(Qt.WindingFill) path_content.addRoundedRect(0, self.title_height, self.width, self.height - self.title_height, self.edge_size, self.edge_size) path_content.addRect(0, self.title_height, self.edge_size, self.edge_size) path_content.addRect(self.width - self.edge_size, self.title_height, self.edge_size, self.edge_size) painter.setPen(Qt.NoPen) painter.setBrush(self._brush_background) painter.drawPath(path_content.simplified()) def initContent(self): self.grContent = QGraphicsProxyWidget(self) self.content.setGeometry( int(self.edge_size), int(self.title_height + self.edge_size), int(self.width - 2*self.edge_size), int(self.height - 2*self.edge_size - self.title_height) ) self.grContent.setWidget(self.content) class Edge(QGraphicsPathItem): def __init__(self, scene_ref, sp, ep, tooltip_text="", parent=None): super().__init__(parent) self._color = QColor("#001000") self._color_selected = QColor("#00ff00") self._color_hover = QColor("red") self._pen = QPen(self._color) self._pen_selected = QPen(self._color_selected) self._pen_hover = QPen(self._color_hover) self._pen.setWidthF(2.0) self._pen_selected.setWidthF(2.0) self._pen_hover.setWidthF(2.0) self.setAcceptHoverEvents(True) self.setFlag(QGraphicsItem.ItemIsSelectable) self.setZValue(-1) self.posSource = [-170, -190] self.posDestination = [100, 100] # 初始化悬停提示文本 self.tooltip = QGraphicsTextItem(self) self.tooltip.setPlainText(tooltip_text) self.tooltip.setFont(QFont("Ubuntu", 10)) self.tooltip.setDefaultTextColor(Qt.white) # 默认隐藏提示 self.tooltip.hide() # 设置提示的背景(可选) self.tooltip_background = QGraphicsRectItem(self) self.tooltip_background.setBrush(QBrush(QColor("#80000000"))) self.tooltip_background.setPen(Qt.NoPen) self.tooltip_background.hide() def paint(self, painter, QStyleOptionGraphicsItem, widget=None): self.updatePath() # 根据状态选择画笔 if self.isSelected(): painter.setPen(self._pen_selected) elif self.isUnderMouse(): painter.setPen(self._pen_hover) else: painter.setPen(self._pen) painter.setBrush(Qt.NoBrush) painter.drawPath(self.path()) def updatePath(self): path = QPainterPath(QPointF(self.posSource[0], self.posSource[1])) path.lineTo(self.posDestination[0], self.posDestination[1]) self.setPath(path) def hoverEnterEvent(self, event): # 计算线条中点位置,用于放置提示文本 mid_x = (self.posSource[0] + self.posDestination[0]) / 2 mid_y = (self.posSource[1] + self.posDestination[1]) / 2 # 调整提示文本位置,避免覆盖线条 self.tooltip.setPos(mid_x - self.tooltip.boundingRect().width()/2, mid_y - 20) # 更新背景矩形大小 bg_rect = self.tooltip.boundingRect().adjusted(-5, -3, 5, 3) self.tooltip_background.setRect(bg_rect) self.tooltip_background.setPos(self.tooltip.pos()) # 显示提示和背景 self.tooltip.show() self.tooltip_background.show() super().hoverEnterEvent(event) def hoverLeaveEvent(self, event): # 隐藏提示 self.tooltip.hide() self.tooltip_background.hide() super().hoverLeaveEvent(event) class MyScene(QGraphicsScene): def __init__(self, parent = None): super().__init__(parent) self.nodes = [] self.edges = [] self.scene_width = 64000 self.scene_height = 64000 self._color_background = QColor("#0af5d2") self.setBackgroundBrush(self._color_background) def addNode(self, node): self.nodes.append(node) class MyView(QGraphicsView): def __init__(self, scene_ref, parent=None): super().__init__(parent) self.scene_ref = scene_ref self.setScene(self.scene_ref) # 开启抗锯齿 self.setRenderHint(QPainter.Antialiasing) if __name__ == '__main__': app = QApplication(sys.argv) wnd = NodeEditorWnd() sys.exit(app.exec_())
关键修改说明
- Edge类初始化添加提示组件:
- 创建
QGraphicsTextItem作为提示文本容器,默认隐藏 - 可选添加半透明背景矩形,提升文本可读性
- 创建
- hover事件处理:
hoverEnterEvent:计算线条中点位置,调整提示文本的显示位置,显示提示和背景hoverLeaveEvent:隐藏提示文本和背景
- 画笔状态优化:
- 区分正常、选中、悬停三种状态的画笔颜色,让交互反馈更清晰
- 视图添加抗锯齿:提升图形显示效果
内容的提问来源于stack exchange,提问作者A.G.Progm.Enthusiast
相关产品推荐
相关产品推荐

