如何在带有孔洞的QGraphicsItem中获取形状的鼠标悬停事件?

6
我在使用Python中的PySide绑定程序中的Qt创造了一个QGraphicsPathItem,其中包含一个大矩形和一个小矩形。由于默认填充规则(Qt.OddEvenFill),内部矩形是透明的。这实际上画了一个带有洞的形状。
现在我想监听鼠标事件,如进入、离开、单击等。我简单的做法是实现QGraphicsItem的hoverEnterEvent等函数,但是当鼠标移到洞口时就不会产生鼠标事件,因为即使洞没有填充,它仍然是图元的一部分。
我想要创建一个QGraphicsItem的导出类,它显示的是一个自定义形状,其轮廓由QPainterPath或一个或多个多边形定义,并且可以有洞。当鼠标进入洞时,应将其视为形状之外。
下面是一个带有洞的例子(当鼠标在内部矩形中时,应将其视为形状的外部,应触发鼠标离开事件):
但是该解决方案也应适用于具有洞的任意形状。
以下是PySide/Python 3.3的示例代码。
from PySide import QtCore, QtGui

class MyPathItem(QtGui.QGraphicsPathItem):

    def __init__(self):
        super().__init__()
        self.setAcceptHoverEvents(True)

    def hoverEnterEvent(self, event):
        print('inside')

    def hoverLeaveEvent(self, event):
        print('outside')

app = QtGui.QApplication([])

scene = QtGui.QGraphicsScene()
path = QtGui.QPainterPath()
path.addRect(0, 0, 100, 100)
path.addRect(25, 25, 50, 50)

item = MyPathItem()
item.setPath(path)
item.setBrush(QtGui.QBrush(QtCore.Qt.blue))

scene.addItem(item)

view = QtGui.QGraphicsView(scene)
view.resize(200, 200)
view.show()

app.exec_()
2个回答

4
似乎QGraphicsItem中的方法shape默认情况下返回包围矩形。返回的路径用于确定位置是在一个复杂形状内还是外。但是,在QGraphicsPathItem的情况下,我们已经有了一条路径,将其返回而不是包围矩形可以解决问题。令人惊讶的是,它确实起了作用。
只需将这两行添加到问题中的QGraphicsPathItem派生类中即可。
def shape(self):
    return self.path()

1
最后看起来很容易,但如果你不知道shape默认总是返回边界矩形,这也有点违反直觉。这就是为什么我在这里留下这个问题的原因。 - Trilarion

0

你可以扩展事件处理程序来检查给定位置是否为特定(内部)路径。不同的方法是使用moveTo/lineTo来绘制(可能会产生歧义)。例如moveTo/lineTo:

from PySide import QtCore, QtGui

class MyPathItem(QtGui.QGraphicsPathItem):

    def __init__(self):
        QtGui.QGraphicsPathItem.__init__(self)
        self.setAcceptHoverEvents(True)

    def hoverEnterEvent(self, event):
        print('inside')

    def hoverLeaveEvent(self, event):
        print('outside')

app = QtGui.QApplication([])

scene = QtGui.QGraphicsScene()

path = QtGui.QPainterPath()
path.moveTo(0, 0)
path.lineTo(100, 0)
path.moveTo(0, 0)
path.lineTo(0, 100)
path.moveTo(100, 100)
path.lineTo(0, 100)
path.moveTo(100, 0)
path.lineTo(100, 100)

item = MyPathItem()
pen = QtGui.QPen()
pen.setWidth(25)
pen.setColor(QtCore.Qt.blue)
item.setPen(pen)
item.setPath(path)

scene.addItem(item)

view = QtGui.QGraphicsView(scene)
view.resize(200, 200)
view.show()

app.exec_()

对于第一个想法,我不确定如何实现。对于第二个想法,我猜更常规的形状可能行不通,因为你用一组粗线替换了一个区域。如果线条的粗细不是始终恒定的,那该怎么办? - Trilarion
第一个想法更加古怪,你必须记住孔径的路径并处理moveEvent https://deptinfo-ensip.univ-poitiers.fr/ENS/pyside-docs/PySide/QtGui/QGraphicsItem.html#PySide.QtGui.PySide.QtGui.QGraphicsItem.hoverMoveEvent - kwarunek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接