QWidget的初始化颜色来自于哪里的笔记

QWidget同时继承于QPaintDevice和QObject两个类,QObject实现元对象系统,QPaintDevice实现画界面功能。

cpp 复制代码
class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice
{
...
}

1、分析paintEvent

是个空函数,啥也没做。
2、分析QWidget画图过程

update()/repaint()

QEvent::UpdateRequest

QWidgetRepaintManager::paintAndFlush()

QWidgetPrivate::drawWidget(...) // 内部私有

QWidget::paintEvent() // 你要重写的函数
可以发现drawWidget函数在paintEvent之前处理了初始化颜色。

cpp 复制代码
void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, DrawWidgetFlags flags,
                                QPainter *sharedPainter, QWidgetRepaintManager *repaintManager)
{
    if (rgn.isEmpty())
        return;
    Q_Q(QWidget);

    qCInfo(lcWidgetPainting) << "Drawing" << rgn << "of" << q << "at" << offset << "into paint device" << pdev << "with" << flags;
    const bool asRoot = flags & DrawAsRoot;
    bool onScreen = shouldPaintOnScreen();
    flags = flags & ~UseEffectRegionBounds;
    const bool alsoOnScreen = flags & DrawPaintOnScreen;
    const bool recursive = flags & DrawRecursive;
    const bool alsoInvisible = flags & DrawInvisible;
    Q_ASSERT(sharedPainter ? sharedPainter->isActive() : true);
    QRegion toBePainted(rgn);
    if (asRoot && !alsoInvisible)
        toBePainted &= clipRect(); //(rgn & visibleRegion());
    if (!(flags & DontSubtractOpaqueChildren))
        subtractOpaqueChildren(toBePainted, q->rect());

    if (!toBePainted.isEmpty()) {
        if (!onScreen || alsoOnScreen) {
            //update the "in paint event" flag
            if (Q_UNLIKELY(q->testAttribute(Qt::WA_WState_InPaintEvent)))
                qWarning("QWidget::repaint: Recursive repaint detected");
            q->setAttribute(Qt::WA_WState_InPaintEvent);

            //clip away the new area
            QPaintEngine *paintEngine = pdev->paintEngine();
            if (paintEngine) {
                setRedirected(pdev, -offset);
                if (sharedPainter)
                    setSystemClip(pdev->paintEngine(), pdev->devicePixelRatio(), toBePainted);
                else
                    paintEngine->d_func()->systemRect = q->data->crect;

                //paint the background
                if ((asRoot || q->autoFillBackground() || onScreen || q->testAttribute(Qt::WA_StyledBackground))
                    && !q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) {
                    beginBackingStorePainting();
                    QPainter p(q);
                    p.setRenderHint(QPainter::SmoothPixmapTransform);
                    paintBackground(&p, toBePainted, (asRoot || onScreen) ? (flags | DrawAsRoot) : DrawWidgetFlags());
                    endBackingStorePainting();
                }

                if (!sharedPainter)
                    setSystemClip(pdev->paintEngine(), pdev->devicePixelRatio(), toBePainted.translated(offset));

                if (!onScreen && !asRoot && !isOpaque && q->testAttribute(Qt::WA_TintedBackground)) {
                    beginBackingStorePainting();
                    QPainter p(q);
                    QColor tint = q->palette().window().color();
                    tint.setAlphaF(.6f);
                    p.fillRect(toBePainted.boundingRect(), tint);
                    endBackingStorePainting();
                }
            }

            bool skipPaintEvent = false;
            if (renderToTexture) {
                // This widget renders into a texture which is composed later. We just need to punch a hole in the backingstore, so the texture will be visible.
                beginBackingStorePainting();
                if (!q->testAttribute(Qt::WA_AlwaysStackOnTop) && repaintManager) {
                    QPainter p(q);
                    p.setCompositionMode(QPainter::CompositionMode_Source);
                    p.fillRect(q->rect(), Qt::transparent);
                } else if (!repaintManager) {
                    // We are not drawing to a backingstore: fall back to QImage
                    QImage img = grabFramebuffer();
                    // grabFramebuffer() always sets the format to RGB32 regardless of whether it is transparent or not.
                    if (img.format() == QImage::Format_RGB32)
                        img.reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied);
                    QPainter p(q);
                    p.drawImage(q->rect(), img);
                    skipPaintEvent = true;
                }
                endBackingStorePainting();

                if (renderToTextureReallyDirty)
                    renderToTextureReallyDirty = 0;
                else
                    skipPaintEvent = true;
            }

            if (!skipPaintEvent) {
                //actually send the paint event
                sendPaintEvent(toBePainted);
            }

            if (repaintManager)
                repaintManager->markNeedsFlush(q, toBePainted, offset);

            //restore
            if (paintEngine) {
                restoreRedirected();
                if (!sharedPainter)
                    paintEngine->d_func()->systemRect = QRect();
                else
                    paintEngine->d_func()->currentClipDevice = nullptr;
                setSystemClip(pdev->paintEngine(), 1, QRegion());
            }
            q->setAttribute(Qt::WA_WState_InPaintEvent, false);
            if (Q_UNLIKELY(q->paintingActive()))
                qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent");

            if (paintEngine && paintEngine->autoDestruct()) {
                delete paintEngine;
            }
        } else if (q->isWindow()) {
            QPaintEngine *engine = pdev->paintEngine();
            if (engine) {
                QPainter p(pdev);
                p.setClipRegion(toBePainted);
                const QBrush bg = q->palette().brush(QPalette::Window);
                if (bg.style() == Qt::TexturePattern)
                    p.drawTiledPixmap(q->rect(), bg.texture());
                else
                    p.fillRect(q->rect(), bg);
                if (engine->autoDestruct())
                    delete engine;
            }
        }
    }

    if (recursive && !children.isEmpty()) {
        paintSiblingsRecursive(pdev, children, children.size() - 1, rgn, offset, flags & ~DrawAsRoot,
                               sharedPainter, repaintManager);
    }
}

paintBackground画默认背景图,通过调色板QPalette获取背景色,然后通过fillRegion画。

cpp 复制代码
void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, DrawWidgetFlags flags) const
{
    Q_Q(const QWidget);
    bool brushOriginSet = false;
    const QBrush autoFillBrush = q->palette().brush(q->backgroundRole());

    // 默认不自动用 backgroundRole 铺底;根窗口等仍可能通过 DrawAsRoot 路径铺 QPalette::Window
    if ((flags & DrawAsRoot) && !(q->autoFillBackground() && autoFillBrush.isOpaque())) {
        const QBrush bg = q->palette().brush(QPalette::Window);
        if (!brushOriginSet)
            brushOriginSet = updateBrushOrigin(painter, bg);
        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);
        }
    }

    // 用 backgroundRole 铺底
    if (q->autoFillBackground()) {
        if (!brushOriginSet)
            brushOriginSet = updateBrushOrigin(painter, autoFillBrush);
        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);
    }
}

真正的画图处理函数fillRegion通过painter画背景色:

cpp 复制代码
static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QBrush &brush)
{
    Q_ASSERT(painter);

    if (brush.style() == Qt::TexturePattern) {
        const QRect rect(rgn.boundingRect());
        painter->setClipRegion(rgn);
        painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
    } else if (brush.gradient()
               && (brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode
                   || brush.gradient()->coordinateMode() == QGradient::ObjectMode)) {
        painter->save();
        painter->setClipRegion(rgn);
        painter->fillRect(0, 0, painter->device()->width(), painter->device()->height(), brush);
        painter->restore();
    } else {
        for (const QRect &rect : rgn)
            painter->fillRect(rect, brush);
    }
}
相关推荐
郝学胜-神的一滴1 天前
Qt 高级开发 024:QSplitter分裂器布局精讲
开发语言·c++·qt·程序人生·用户界面
-凌凌漆-1 天前
【Qt】std::shared_ptr<>与std::make_shared<>
开发语言·qt
郝学胜_神的一滴1 天前
Qt 高级开发 025:打造优雅界面的艺术与高效重构之道
c++·qt
十五年专注C++开发1 天前
Qt之QScopedPointer、QScopeGuard、QScopedValueRollback使用及源码解读
开发语言·c++·qt·qscopedpointer·qscopeguard
yugi9878381 天前
基于Qt的实用二维码生成解决方案
开发语言·qt
不爱吃糖的程序媛1 天前
环境搭建教程:HarmonyOS PC 录屏工具(Qt5 + OHOS Native Media)
qt·华为·harmonyos
-凌凌漆-1 天前
【Qt】C++中protected与private的区别
开发语言·c++·qt
-凌凌漆-1 天前
Qt QML应用层框架
开发语言·qt
走好每一步2 天前
1、VTK+QT + cmake编程 三维圆柱体
qt·vtk
小小码农Come on2 天前
Qt::WA_StyledBackground属性的作用
开发语言·qt