为啥当 QPushButton::paintEvent 后面跟着 QPainter::fillRect 时应用程序会崩溃?
Posted
技术标签:
【中文标题】为啥当 QPushButton::paintEvent 后面跟着 QPainter::fillRect 时应用程序会崩溃?【英文标题】:Why the application crashes when QPushButton::paintEvent is followed by QPainter::fillRect?为什么当 QPushButton::paintEvent 后面跟着 QPainter::fillRect 时应用程序会崩溃? 【发布时间】:2018-10-28 03:46:21 【问题描述】:我正在通过子类化QPushButton
并处理paintEvent
来实现一个圆形按钮。我想显示用户设置的文字,然后画一个圆圈。
应用程序在调用QPushButton::paintEvent
方法后在QPainter::fillRect
崩溃。如果不调用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】:原因
你首先创建一个painter,将QPaintDevice *device
传递给QPainter
的构造函数,其中callsQPainter::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);
该示例产生以下结果:
如您所见,文本与您的自定义绘图一起显示。
【讨论】:
以上是关于为啥当 QPushButton::paintEvent 后面跟着 QPainter::fillRect 时应用程序会崩溃?的主要内容,如果未能解决你的问题,请参考以下文章
为啥当状态发生突变时 mapStateToProps 返回空对象?