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);
    }
}
相关推荐
小陶来咯3 小时前
aimrt中间件的使用
开发语言·qt·中间件
music score4 小时前
google 的C++自动化测试框架详解(Google Test)(2)
c++·qt·lucene
小短腿的代码世界4 小时前
Qt_Qwt深度解析:从源码到工业级性能优化
开发语言·qt·性能优化
GoKu~4 小时前
QT Qss
qt
基德爆肝c语言5 小时前
Qt系统相关
开发语言·qt
星河漫步Lu6 小时前
QT6中五步完成Android的环境配置
android·qt
小短腿的代码世界6 小时前
Qt状态机框架深度解析:从状态图到事件驱动闭环
开发语言·qt
学习,学习,在学习6 小时前
Q工控仪器程序框架设计详解(工控)
c++·qt·架构·qt5
郝学胜-神的一滴6 小时前
Qt 高级开发 004: 三大窗口类深度解析
开发语言·c++·qt·程序人生·系统架构