为什么在QPinterButton :: paintEvent之后跟QPainter :: fillRect导致应用程序崩溃?

时间:2018-10-28 03:46:21

标签: c++ qt qt5

我正在通过子类QPushButton和处理paintEvent来实现圆形按钮。我想显示用户设置的文本,然后画一个圆。

调用QPainter::fillRect方法后,应用程序在QPushButton::paintEvent崩溃。如果未调用QPushButton::paintEvent,则不会崩溃,但不会显示按钮文本。

这是我的代码:

class CRoundAnimatingBtn : public QPushButton
{
    Q_OBJECT
public:
    explicit CRoundAnimatingBtn(QWidget *parent = nullptr)  : QPushButton(parent) {}

protected:
    void resizeEvent(QResizeEvent *) { setMask(QRegion(rect(), QRegion::Ellipse)); }
    void paintEvent(QPaintEvent * e) {
        QPainter painter(this);
        QPointF center(width()/2, height()/2);
        QRadialGradient radialGradient(center, qMin(width(), height())/2, center);

        QPushButton::paintEvent(e); // Application crashes if this is called

        if (isDown()) {
            radialGradient.setColorAt(0.0,Qt::transparent);
            radialGradient.setColorAt(0.79, Qt::transparent);
            radialGradient.setColorAt(0.80, Qt::gray);
            radialGradient.setColorAt(0.95, Qt::black);
            radialGradient.setColorAt(0.90, Qt::gray);
            radialGradient.setColorAt(0.91, Qt::transparent);
        } else {
            radialGradient.setColorAt(0.0,Qt::transparent);
            radialGradient.setColorAt(0.84, Qt::transparent);
            radialGradient.setColorAt(0.85, Qt::gray);
            radialGradient.setColorAt(0.90, Qt::black);
            radialGradient.setColorAt(0.95, Qt::gray);
            radialGradient.setColorAt(0.96, Qt::transparent);
        }

        painter.fillRect(rect(), radialGradient); // Application crashes here
    }
};

如何修复崩溃?

1 个答案:

答案 0 :(得分:1)

原因

您首先创建一个画家,将QPaintDevice *device传递给QPainter的构造函数,calls QPainter::begin

QPainter painter(this);

然后您将其的基类实现称为 paintEvent

QPushButton::paintEvent(e);

在完成第一个涂漆设备之前,它会在相同的涂漆设备上创建一个新的涂漆器QStylePainter p

void QPushButton::paintEvent(QPaintEvent *)
{
    QStylePainter p(this);
    QStyleOptionButton option;
    initStyleOption(&option);
    p.drawControl(QStyle::CE_PushButton, option);
}

最后,您尝试使用以下方法与第一位画家QPainter painter进行绘制:

painter.fillRect(rectangle, radialGradient);

重要提示::这种方法是不允许的,因为QPainter::begin的文档明确指出:

  

警告:油漆设备一次只能由一位油漆工油漆。

解决方案

考虑到这一点,我建议您通过将QPushButton::paintEvent(e);移到CRoundAnimatingBtn::paintEvent的开头(在此事件处理程序中的所有其他功能之前)来避免同时拥有两个活动的绘画程序。 / p>

注意:如果您将QPushButton::paintEvent(e);放在CRoundAnimatingBtn::paintEvent的最后,则默认实现会覆盖您的自定义图形,因此将不可见。

示例

CRoundAnimatingBtn::paintEvent的外观如下:

void paintEvent(QPaintEvent * e) {
        QPushButton::paintEvent(e);

        QPainter painter(this);
        QPointF center(width()/2, height()/2);
        QRadialGradient radialGradient(center, qMin(width(), height())/2, center);

        ...

        painter.fillRect(rect(), radialGradient);
    }

该示例将产生以下结果:

Window with a round highlighted button

如您所见,文本与您的自定义图形一起显示。