Почему происходит сбой приложения, когда за QPushButton :: paintEvent следует QPainter :: fillRect? - PullRequest
0 голосов
/ 28 октября 2018

Я реализую круглую кнопку путем подкласса 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 голосов
/ 28 октября 2018

Причина

Сначала вы создаете художник, передавая QPaintDevice *device конструктору QPainter, который вызывает 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 (до всего остального в этом обработчике событий).

Примечание: Если вы поставите 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

Как видите, текст отображается вместе с вашим пользовательским рисунком.

...