0

I am trying to show a connection by a line (using QGraphicsPathItem) and display a text when I mouse hover on that line. However, I am not able to bring up a text during mouse hover on the line.
A basic working version of the application code is below. Inside, class Edge, I have written a hoverEnterEvent which is working when I mouse hover on the line. Not sure, how to display the text on it.
Any help on showing the text on mouse hover will be very nice.

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QGraphicsView

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)

        # crate graphics scene
        self.scene = MyScene()
        # self.grScene = self.scene.grScene

        self.addNodes()

        # create graphics view
        #self.view = QDMGraphicsView(self.scene.grScene, self)
        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])
        print ("This is addNodes..")
        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):
        # title
        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())

        # content
        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.content.setGeometry(self.edge_size, self.title_height + self.edge_size, self.width - 2*self.edge_size, self.height - 2*self.edge_size-self.title_height)
        self.grContent.setWidget(self.content)

class Edge(QGraphicsPathItem):
    def __init__(self, scene_ref, sp,ep,  parent=None):
        super().__init__(parent)
        self._color = QColor("#001000")
        self._color_selected = QColor("#00ff00")
        self._pen = QPen(self._color)
        self._pen_selected = QPen(self._color_selected)
        self._pen.setWidthF(2.0)
        self._pen_selected.setWidthF(2.0)
        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable)

        self.setZValue(-1)

        self.posSource = [-170, -190]
        self.posDestination = [100, 100]



    def paint(self, painter, QStyleOptionGraphicsItem, widget=None):
        self.updatePath()

        painter.setPen(self._pen if not self.isSelected() else self._pen_selected)
        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):
        print ("Inside mouse hover event ------\n")
        color = QColor("red")
        pen = self.pen()
        pen.setColor(color)
        self.setPen(pen)
        QGraphicsItem.hoverMoveEvent(self, 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.initUI()
        self.scene_ref = scene_ref
        self.setScene(self.scene_ref)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    wnd = NodeEditorWnd()
    sys.exit(app.exec_())

Thanks

  • 1
    You need to create a widget to contain the text. For anything that inherits from Qwidget you can use the Qtooltip, but I'm not sure about QGraphicItems. – MappingThePast Aug 18 '23 at 10:56

1 Answers1

0

I could achieve it by adding

QGraphicsItem.setToolTip(self, "100") 

in the hoverEnterEvent function
Full code below:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QGraphicsView

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)

        # crate graphics scene
        self.scene = MyScene()
        # self.grScene = self.scene.grScene

        self.addNodes()

        # create graphics view
        #self.view = QDMGraphicsView(self.scene.grScene, self)
        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])
        print ("This is addNodes..")
        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):
        # title
        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())

        # content
        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.content.setGeometry(self.edge_size, self.title_height + self.edge_size, self.width - 2*self.edge_size, self.height - 2*self.edge_size-self.title_height)
        self.grContent.setWidget(self.content)

class Edge(QGraphicsPathItem):
    def __init__(self, scene_ref, sp,ep,  parent=None):
        super().__init__(parent)
        self._color = QColor("#001000")
        self._color_selected = QColor("#00ff00")
        self._pen = QPen(self._color)
        self._pen_selected = QPen(self._color_selected)
        self._pen.setWidthF(2.0)
        self._pen_selected.setWidthF(2.0)
        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable)

        self.setZValue(-1)

        self.posSource = [-170, -190]
        self.posDestination = [100, 100]



    def paint(self, painter, QStyleOptionGraphicsItem, widget=None):
        self.updatePath()

        painter.setPen(self._pen if not self.isSelected() else self._pen_selected)
        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):
        print ("Inside mouse hover event ------\n")
        color = QColor("red")
        pen = self.pen()
        pen.setColor(color)
        self.setPen(pen)
        QGraphicsItem.hoverMoveEvent(self, event)
        QGraphicsItem.setToolTip(self, "100") 



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.initUI()
        self.scene_ref = scene_ref
        self.setScene(self.scene_ref)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    wnd = NodeEditorWnd()
    sys.exit(app.exec_())