在悬停事件时激活 QPainter

Posted

技术标签:

【中文标题】在悬停事件时激活 QPainter【英文标题】:Activating QPainter upon hover event 【发布时间】:2017-02-09 19:10:38 【问题描述】:

这里有一些代码可以说明我的问题:

import sys
from PyQt4 import QtGui, QtCore


class CustomButton(QtGui.QAbstractButton):
    def __init__(self, *__args):
        super().__init__(*__args)
        self.setFixedSize(190, 50)
        self.installEventFilter(self)

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.setBrush(QtGui.QColor(136, 212, 78))
        painter.setPen(QtCore.Qt.NoPen)
        painter.drawRect(QtCore.QRect(0, 0, 100, 48))

    def eventFilter(self, object, event):
        if event.type() == QtCore.QEvent.HoverMove:
            painter = QtGui.QPainter(self)
            painter.begin(self)
            painter.drawRect(QtCore.QRect(0, 0, 100, 48))
            painter.end()
            return True
        return False

app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
layout = QtGui.QGridLayout(window)

button = CustomButton()
layout.addWidget(button, 0, 0)

window.show()
sys.exit(app.exec_())

目标是使用QPainter 制作一个可以在检测到HoverMove 事件时修改的按钮。但是,悬停时出现以下错误:

QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::drawRects: Painter not active
QPainter::end: Painter not active, aborted

根据我从文档 (here) 中了解到的信息,我可以使用 .begin() 来激活 QPainter;但是,正如错误消息显示的那样,情况并非如此,并且第二个矩形没有被绘制。我应该如何使用QPainter 来实现所需的输出?

【问题讨论】:

正如文档所说:“警告:当paintdevice是一个小部件时,QPainter只能在paintEvent()函数或由paintEvent()调用的函数中使用; 除非设置了 Qt.WA_PaintOutsidePaintEvent 小部件属性。在 Mac OS X 和 Windows 上,无论该属性的设置如何,您都只能在 paintEvent() 函数中进行绘制。" 糟糕,我的错,错过了最重要的部分:/。如果它只能在paintEvent() 中使用,是否可以从带有参数的事件处理程序中调用此方法? 【参考方案1】:

您需要检测到paintEvent 内的悬停并采取相应措施:

    def paintEvent(self, event):
        option = QtGui.QStyleOptionButton()
        option.initFrom(self)
        painter = QtGui.QPainter(self)
        if option.state & QtGui.QStyle.State_MouseOver:
            # do hover stuff ...
        else:
            # do normal stuff ...

QStyleOption 及其子类包含QStyle 函数绘制图形元素所需的所有信息。 QPaintEvent 仅包含有关需要更新哪些区域的信息。

【讨论】:

谢谢!这似乎可以解决问题。但是,最好在函数结束时准确地指出painter.end(),否则程序将崩溃。在我接受之前,您介意解释一下QStyleOptionButton 的使用而不是检查事件的类型吗? 我已经添加了一些进一步的解释,但所有细节都可以在 Qt 文档中找到。没有必要显式调用end(),因为它是由析构函数自动调用的。检查事件的类型是没有意义的,因为它只能是QPaintEvent 调用option.initFrom(self) 只是将self.underMouse() 的结果添加到option.state @MarcheRemi 这不是这样做的重点。绘制自定义小部件比获取鼠标悬停状态要多得多。样式选项提供了一种非常有效的方式,可以在一个步骤中获取所有相关信息。 @ekhumoro,这个问题是关于悬停的。【参考方案2】:

@ekhumoro's answer above 可以用QWidget::underMouse() 更简单地重写。 the docs

    def paintEvent(self, event):
        if underMouse():
            # do hover stuff ...
        else:
            # do normal stuff ...

【讨论】:

以上是关于在悬停事件时激活 QPainter的主要内容,如果未能解决你的问题,请参考以下文章

jQuery悬停仅在悬停一定时间时才起作用

溢出:滚动停止悬停状态激活

使用 tkinter 悬停时更改按钮颜色

Vuetify VTooltip 仅在激活器单击时触发

Mac Chrome 悬停事件在窗口最大化时表现不同

如何在点击时禁用鼠标悬停事件?