自定义继承QWidget样式表不生效

465 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、前言

做一个简单的展示界面,所以继承了QWidget,然后在ui里撸了一通样式表之后,运行起来一看,样式啥也没有,内心很崩溃,这个时候不用慌,以下三种办法可供使用

二、解决方案

void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, int flags) const
{
    Q_Q(const QWidget);

#if QT_CONFIG(scrollarea)
    bool resetBrushOrigin = false;
    QPointF oldBrushOrigin;
    //If we are painting the viewport of a scrollarea, we must apply an offset to the brush in case we are drawing a texture
    QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(parent);
    if (scrollArea && scrollArea->viewport() == q) {
        QObjectData *scrollPrivate = static_cast<QWidget *>(scrollArea)->d_ptr.data();
        QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(scrollPrivate);
        oldBrushOrigin = painter->brushOrigin();
        resetBrushOrigin = true;
        painter->setBrushOrigin(-priv->contentsOffset());

    }
#endif // QT_CONFIG(scrollarea)

    const QBrush autoFillBrush = q->palette().brush(q->backgroundRole());

    if ((flags & DrawAsRoot) && !(q->autoFillBackground() && autoFillBrush.isOpaque())) {
        const QBrush bg = q->palette().brush(QPalette::Window);
        if (!(flags & DontSetCompositionMode)) {
            //copy alpha straight in
            QPainter::CompositionMode oldMode = painter->compositionMode();
            painter->setCompositionMode(QPainter::CompositionMode_Source);
            fillRegion(painter, rgn, bg);
            painter->setCompositionMode(oldMode);
        } else {
            fillRegion(painter, rgn, bg);
        }
    }

    if (q->autoFillBackground())
        fillRegion(painter, rgn, autoFillBrush);

    if (q->testAttribute(Qt::WA_StyledBackground)) {
        painter->setClipRegion(rgn);
        QStyleOption opt;
        opt.initFrom(q);
        q->style()->drawPrimitive(QStyle::PE_Widget, &opt, painter, q);
    }

#if QT_CONFIG(scrollarea)
    if (resetBrushOrigin)
        painter->setBrushOrigin(oldBrushOrigin);
#endif // QT_CONFIG(scrollarea)
}
  1. 在QWidget中绘制背景的源码中,判断了一个WA_StyledBackground属性,只有为true时,才会去绘制背景样式,但是这个属性默认是false,也就是不绘制背景样式了,所以要解决问题,只需要将该属性设置为true就好了。

  2. 继承QFrame,因为QFrame就是专门用来承载样式的,所以本身已经对样式做了支持

void QFrame::paintEvent(QPaintEvent *)
{
    QPainter paint(this);
    drawFrame(&paint);
}

/*!
    \internal

    Used by QLabel and QLCDNumber
 */
void QFrame::drawFrame(QPainter *p)
{
    QStyleOptionFrame opt;
    initStyleOption(&opt);
    style()->drawControl(QStyle::CE_ShapedFrame, &opt, p, this);
}
  1. 重写paintEvent,手动处理 从刚刚的源码中可以看到判断了WA_StyledBackground属性之后做了这段处理
if (q->testAttribute(Qt::WA_StyledBackground)) {
        painter->setClipRegion(rgn);
        QStyleOption opt;
        opt.initFrom(q);
        q->style()->drawPrimitive(QStyle::PE_Widget, &opt, painter, q);
    }

所以,我们只需要把这段绘制背景样式的代码手动写出来,也能解决问题

void ChildWidget::paintEvent(QPaintEvent*)
{
    QStyleOption option;
    option.init(this);
    QPainter painter(this);
    style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this);
}

三、结言

如果在没设置样式的情况下,建议还是将WA_StyledBackground属性关掉,毕竟加载动作也是消耗很大的。

创作不易,留个赞再走吧!如果对文章内容有任何指正,欢迎评论!