Reputation: 198
I am implementing a round button by subclassing QPushButton
and handling the paintEvent
. I want to show the text set by the user and then draw a circle.
The application crashes at QPainter::fillRect
after calling the QPushButton::paintEvent
method. If QPushButton::paintEvent
is not called it does not crash, but the button text is not shown.
Here is my code:
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
}
};
How to fix the crash?
Upvotes: 1
Views: 475
Reputation: 8399
You first create a painter, passing a QPaintDevice *device
to the constructor of QPainter
, which calls QPainter::begin
:
QPainter painter(this);
Then you call the base class implementation of
paintEvent
:
QPushButton::paintEvent(e);
which creates a new painter QStylePainter p
on the same paint device, before you are done with the first one:
void QPushButton::paintEvent(QPaintEvent *)
{
QStylePainter p(this);
QStyleOptionButton option;
initStyleOption(&option);
p.drawControl(QStyle::CE_PushButton, option);
}
Finally, you try to draw with the first painter QPainter painter
using:
painter.fillRect(rectangle, radialGradient);
Important: Such approach is not allowed, as the documentation of QPainter::begin
clearly says:
Warning: A paint device can only be painted by one painter at a time.
Having this in mind, I would suggest you to avoid having two active painters at the same time by moving QPushButton::paintEvent(e);
to the very beginning of CRoundAnimatingBtn::paintEvent
(before everything else in this event handler).
Note: If you put QPushButton::paintEvent(e);
at the very end of CRoundAnimatingBtn::paintEvent
, the default implementation will overpaint your custom drawing and it would not be visible.
Here is how the CRoundAnimatingBtn::paintEvent
might look like:
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);
}
The example produces the following result:
As you see, the text is shown together with your custom drawing.
Upvotes: 2