【问题标题】:Mouse hover over a PySide QGraphicsPathItem鼠标悬停在 PySide QGraphicsPathItem
【发布时间】:2018-05-15 10:11:04
【问题描述】:

当我尝试在 QGraphicsPathItem 上注册鼠标悬停事件时,我遇到了奇怪的行为。

在示例代码(我从 qt5 弹性节点示例中破解)中,我绘制了一条简单的曲线。悬停在曲线上会改变曲线的颜色,但悬停事件不会记录在曲线的右下半部分。此外,实际上只有曲线的左上半部分会改变颜色。

我添加了一个 QPainterPathStroker,认为悬停事件会在该区域内注册,但事实并非如此。

我的目标是将鼠标移入、移入和移出 QPainterPathStroker 区域注册为 QGraphicsPathItem 上的悬停事件。

感谢任何帮助。谢谢

from PySide import QtCore, QtGui

class Edge(QtGui.QGraphicsPathItem):

    def __init__(self):
        QtGui.QGraphicsPathItem.__init__(self)
        self.setAcceptsHoverEvents(True)
        path = QtGui.QPainterPath()
        x1 = -100
        x2 = 120
        y1 = -100
        y2 = 120
        dx = abs(x1-x2)/2
        dy = abs(y1-y2)/2
        a = QtCore.QPointF(x1, y1)
        b = QtCore.QPointF(x1+dx, y1)
        c = QtCore.QPointF(x2-dy, y2)
        d = QtCore.QPointF(x2, y2)
        path.moveTo(a)
        path.cubicTo(b,c,d)
        self.setPath(path)

        self.hover = False

    def hoverEnterEvent(self, event):

        self.hover = True
        QtGui.QGraphicsPathItem.hoverEnterEvent(self, event)

    def hoverMoveEvent(self, event):

        QtGui.QGraphicsPathItem.hoverMoveEvent(self, event)

    def hoverLeaveEvent(self, event):

        self.hover = False
        QtGui.QGraphicsPathItem.hoverLeaveEvent(self, event)        

    def boundingRect(self):
        return QtCore.QRectF(-100,-100,120,120)

    def paint(self, painter, option, widget):

        if self.hover:
            c = QtCore.Qt.red
        else:
            c = QtCore.Qt.black
        painter.setPen(QtGui.QPen(c, 10, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
        painter.drawPath(self.path())

        painter.setPen(QtGui.QPen(QtCore.Qt.blue, 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
        painter.drawPath(self.shape())

    def shape(self):
        s = QtGui.QPainterPathStroker()    
        s.setWidth(30)
        s.setCapStyle(QtCore.Qt.RoundCap)
        path = s.createStroke(self.path())
        return path


class GraphWidget(QtGui.QGraphicsView):
    def __init__(self):
        QtGui.QGraphicsView.__init__(self)

        scene = QtGui.QGraphicsScene(self)
        scene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex)
        scene.setSceneRect(-200, -200, 400, 400)
        self.setScene(scene)
        self.setRenderHint(QtGui.QPainter.Antialiasing)
        self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)

        self.edge = Edge()
        scene.addItem(self.edge)

        self.scale(0.8, 0.8)
        self.setMinimumSize(400, 400)
        self.setWindowTitle(self.tr("Elastic Nodes"))

    def wheelEvent(self, event):
        self.scaleView(math.pow(2.0, -event.delta() / 240.0))

    def drawBackground(self, painter, rect):
        sceneRect = self.sceneRect()
        rightShadow = QtCore.QRectF(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height())
        bottomShadow = QtCore.QRectF(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5)
        if rightShadow.intersects(rect) or rightShadow.contains(rect):
            painter.fillRect(rightShadow, QtCore.Qt.darkGray)
        if bottomShadow.intersects(rect) or bottomShadow.contains(rect):
            painter.fillRect(bottomShadow, QtCore.Qt.darkGray)

        gradient = QtGui.QLinearGradient(sceneRect.topLeft(), sceneRect.bottomRight())
        gradient.setColorAt(0, QtCore.Qt.white)
        gradient.setColorAt(1, QtCore.Qt.lightGray)
        painter.fillRect(rect.intersect(sceneRect), QtGui.QBrush(gradient))
        painter.setBrush(QtCore.Qt.NoBrush)
        painter.drawRect(sceneRect)

    def scaleView(self, scaleFactor):
        factor = self.matrix().scale(scaleFactor, scaleFactor).mapRect(QtCore.QRectF(0, 0, 1, 1)).width()

        if factor < 0.07 or factor > 100:
            return

        self.scale(scaleFactor, scaleFactor)

    def mouseMoveEvent(self, event):

        self.edge.update()
        QtGui.QGraphicsView.mouseMoveEvent(self, event)


widget = GraphWidget()
widget.show()

【问题讨论】:

    标签: python pyside qgraphicsview qgraphicsscene qgraphicspathitem


    【解决方案1】:

    这种情况下的问题是boundingRect()没有覆盖完整的path(),这是paint()方法使用的,解决方法是返回self.shape().boundingRect()

    class Edge(QtGui.QGraphicsPathItem):
        def __init__(self):
            QtGui.QGraphicsPathItem.__init__(self)
            self.setAcceptsHoverEvents(True)
            path = QtGui.QPainterPath()
            x1 = -100
            x2 = 120
            y1 = -100
            y2 = 120
            dx = abs(x1-x2)/2
            dy = abs(y1-y2)/2
            a = QtCore.QPointF(x1, y1)
            b = a + QtCore.QPointF(dx, 0)
            d = QtCore.QPointF(x2, y2)
            c = d - QtCore.QPointF(dy, 0)
            path.moveTo(a)
            path.cubicTo(b,c,d)
            self.setPath(path)
    
            self.hover = False
    
        def hoverEnterEvent(self, event):
            QtGui.QGraphicsPathItem.hoverEnterEvent(self, event)
            self.hover = True
            self.update()
    
        def hoverMoveEvent(self, event):
            # print(event)
            QtGui.QGraphicsPathItem.hoverMoveEvent(self, event)
    
        def hoverLeaveEvent(self, event):
            QtGui.QGraphicsPathItem.hoverLeaveEvent(self, event)
            self.hover = False
            self.update()        
    
        def boundingRect(self):
            return self.shape().boundingRect()
    
        def paint(self, painter, option, widget):
            c = QtCore.Qt.red if self.hover else QtCore.Qt.black
            painter.setPen(QtGui.QPen(c, 10, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
            painter.drawPath(self.path())
    
            painter.setPen(QtGui.QPen(QtCore.Qt.blue, 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
            painter.drawPath(self.shape())
    
        def shape(self):
            s = QtGui.QPainterPathStroker()    
            s.setWidth(30)
            s.setCapStyle(QtCore.Qt.RoundCap)
            path = s.createStroke(self.path())
            return path
    

    【讨论】:

    • 是的,就是这样。谢谢
    【解决方案2】:

    对于 PySide2,上面的代码有两个问题:

    Edge.__init__ 中而不是

    self.setAcceptsHoverEvents(True)
    

    使用:

    self.setAcceptHoverEvents(True)
    

    (方法名中不带“s”)。

    GraphWidget.drawBackground,而不是

    painter.fillRect(rect.intersects(sceneRect), QBrush(gradient))
    

    使用其中之一

    painter.fillRect(rect.intersected(sceneRect), QBrush(gradient))
    

    (方法名称中的'ed'而不是's')或

    painter.fillRect(rect & sceneRect, QBrush(gradient))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-04
      • 2018-09-03
      • 2015-04-22
      • 2011-05-26
      • 2017-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多