Qt源码分析--QWidget(9)--System functions

1.QWidget *parentWidget() const;

inline QWidget *QWidget::parentWidget() const
{ return static_cast<QWidget *>(QObject::parent()); }

2.QWidget *window() const;


QWidget *QWidget::window() const
{
    QWidget *w = const_cast<QWidget *>(this);
    QWidget *p = w->parentWidget();
    while (!w->isWindow() && p) {
        w = p;
        p = p->parentWidget();
    }
    return w;
}

如果QWidget本身是window,则返回自身;否则,往上寻找祖先控件,直到找到带边框的控件为止。

3.void setParent(QWidget *parent);

void QWidget::setParent(QWidget *parent)
{
    if (parent == parentWidget())
        return;
    setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask);
}

void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
{
    Q_D(QWidget);
    Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QWidget to itself");
#ifdef QT_DEBUG
    const auto checkForParentChildLoops = qScopeGuard([&](){
        int depth = 0;
        auto p = parentWidget();
        while (p) {
            if (++depth == QObjectPrivate::CheckForParentChildLoopsWarnDepth) {
                qWarning("QWidget %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
                         "this is undefined behavior",
                         this, metaObject()->className(), qPrintable(objectName()));
            }
            p = p->parentWidget();
        }
    });
#endif
    bool resized = testAttribute(Qt::WA_Resized);
    bool wasCreated = testAttribute(Qt::WA_WState_Created);
    QWidget *oldtlw = window();
    if (f & Qt::Window) // Frame geometry likely changes, refresh.
        d->data.fstrut_dirty = true;
    QWidget *desktopWidget = 0;
    if (parent && parent->windowType() == Qt::Desktop)
        desktopWidget = parent;
    bool newParent = (parent != parentWidget()) || !wasCreated || desktopWidget;
    if (newParent && parent && !desktopWidget) {
        if (testAttribute(Qt::WA_NativeWindow) && !QCoreApplication::testAttribute(Qt::AA_DontCreateNativeWidgetSiblings))
            parent->d_func()->enforceNativeChildren();
        else if (parent->d_func()->nativeChildrenForced() || parent->testAttribute(Qt::WA_PaintOnScreen))
            setAttribute(Qt::WA_NativeWindow);
    }
    if (wasCreated) {
        if (!testAttribute(Qt::WA_WState_Hidden)) {
            hide();
            setAttribute(Qt::WA_WState_ExplicitShowHide, false);
        }
        if (newParent) {
            QEvent e(QEvent::ParentAboutToChange);
            QCoreApplication::sendEvent(this, &e);
        }
    }
    if (newParent && isAncestorOf(focusWidget()))
        focusWidget()->clearFocus();
    QTLWExtra *oldTopExtra = window()->d_func()->maybeTopData();
    QWidgetBackingStoreTracker *oldBsTracker = oldTopExtra ? &oldTopExtra->backingStoreTracker : 0;
    d->setParent_sys(parent, f);
    QTLWExtra *topExtra = window()->d_func()->maybeTopData();
    QWidgetBackingStoreTracker *bsTracker = topExtra ? &topExtra->backingStoreTracker : 0;
    if (oldBsTracker && oldBsTracker != bsTracker)
        oldBsTracker->unregisterWidgetSubtree(this);
    if (desktopWidget)
        parent = 0;
#ifndef QT_NO_OPENGL
    if (d->textureChildSeen && parent) {
        // set the textureChildSeen flag up the whole parent chain
        QWidgetPrivate::get(parent)->setTextureChildSeen();
    }
#endif
    if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) {
        if (newParent)
            oldBs->removeDirtyWidget(this);
        // Move the widget and all its static children from
        // the old backing store to the new one.
        oldBs->moveStaticWidgets(this);
    }
    // ### fixme: Qt 6: Remove AA_ImmediateWidgetCreation.
    if (QApplicationPrivate::testAttribute(Qt::AA_ImmediateWidgetCreation) && !testAttribute(Qt::WA_WState_Created))
        create();
    d->reparentFocusWidgets(oldtlw);
    setAttribute(Qt::WA_Resized, resized);
    const bool useStyleSheetPropagationInWidgetStyles =
        QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles);
    if (!useStyleSheetPropagationInWidgetStyles && !testAttribute(Qt::WA_StyleSheet)
        && (!parent || !parent->testAttribute(Qt::WA_StyleSheet))) {
        d->resolveFont();
        d->resolvePalette();
    }
    d->resolveLayoutDirection();
    d->resolveLocale();
    // Note: GL widgets under WGL or EGL will always need a ParentChange
    // event to handle recreation/rebinding of the GL context, hence the
    // (f & Qt::MSWindowsOwnDC) clause (which is set on QGLWidgets on all
    // platforms).
    if (newParent
#if 0 /* Used to be included in Qt4 for Q_WS_WIN */ || defined(QT_OPENGL_ES)
        || (f & Qt::MSWindowsOwnDC)
#endif
        ) {
        // propagate enabled updates enabled state to non-windows
        if (!isWindow()) {
            if (!testAttribute(Qt::WA_ForceDisabled))
                d->setEnabled_helper(parent ? parent->isEnabled() : true);
            if (!testAttribute(Qt::WA_ForceUpdatesDisabled))
                d->setUpdatesEnabled_helper(parent ? parent->updatesEnabled() : true);
        }
        d->inheritStyle();
        // send and post remaining QObject events
        if (parent && d->sendChildEvents) {
            QChildEvent e(QEvent::ChildAdded, this);
            QCoreApplication::sendEvent(parent, &e);
        }
//### already hidden above ---> must probably do something smart on the mac
// #if 0 // Used to be included in Qt4 for Q_WS_MAC
//             extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
//             if(!qt_mac_is_macdrawer(q)) //special case
//                 q->setAttribute(Qt::WA_WState_Hidden);
// #else
//             q->setAttribute(Qt::WA_WState_Hidden);
//#endif
        if (parent && d->sendChildEvents && d->polished) {
            QChildEvent e(QEvent::ChildPolished, this);
            QCoreApplication::sendEvent(parent, &e);
        }
        QEvent e(QEvent::ParentChange);
        QCoreApplication::sendEvent(this, &e);
    }
#ifndef QT_NO_OPENGL
    //renderToTexture widgets also need to know when their top-level window changes
    if (d->textureChildSeen && oldtlw != window()) {
        sendWindowChangeToTextureChildrenRecursively(this);
    }
#endif
    if (!wasCreated) {
        if (isWindow() || parentWidget()->isVisible())
            setAttribute(Qt::WA_WState_Hidden, true);
        else if (!testAttribute(Qt::WA_WState_ExplicitShowHide))
            setAttribute(Qt::WA_WState_Hidden, false);
    }
    d->updateIsOpaque();
#if QT_CONFIG(graphicsview)
    // Embed the widget into a proxy if the parent is embedded.
    // ### Doesn't handle reparenting out of an embedded widget.
    if (oldtlw->graphicsProxyWidget()) {
        if (QGraphicsProxyWidget *ancestorProxy = d->nearestGraphicsProxyWidget(oldtlw))
            ancestorProxy->d_func()->unembedSubWindow(this);
    }
    if (isWindow() && parent && !graphicsProxyWidget() && !bypassGraphicsProxyWidget(this)) {
        if (QGraphicsProxyWidget *ancestorProxy = d->nearestGraphicsProxyWidget(parent))
            ancestorProxy->d_func()->embedSubWindow(this);
    }
#endif
    if (d->extra && d->extra->hasWindowContainer)
        QWindowContainer::parentWasChanged(this);
}

如果新的父窗口widget位于不同的窗口中,则QWidget及其子窗口将附加到新父窗口widget的选项卡的末尾,内部顺序与以前相同。

4.WId winId() const;

WId QWidget::winId() const
{
    if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
#ifdef ALIEN_DEBUG
        qDebug() << "QWidget::winId: creating native window for" << this;
#endif
        QWidget *that = const_cast<QWidget*>(this);
        that->setAttribute(Qt::WA_NativeWindow);
        that->d_func()->createWinId();
        return that->data->winid;
    }
    return data->winid;
}

5.static QWidget *find(WId);

QWidget *QWidget::find(WId id)
{
    return QWidgetPrivate::mapper ? QWidgetPrivate::mapper->value(id, 0) : nullptr;
}

### 如何在 Qt 中使用 OpenGL 进行纹理映射 为了实现基于 Qt 和 OpenGL 的纹理映射,开发者通常会创建继承自 `QOpenGLWidget` 类的小部件来管理渲染上下文并重载其虚函数以定义绘制逻辑。下面是一个简单的例子展示如何加载图片作为纹理应用到矩形上[^1]。 #### 创建 QOpenGLWidget 子类 首先需要构建一个从 `QOpenGLWidget` 继承而来的子类,在其中初始化 OpenGL 资源以及设置好要使用的着色器程序: ```cpp #include <QOpenGLWidget> #include <QOpenGLShaderProgram> #include <QOpenGLTexture> class GLWidget : public QOpenGLWidget { Q_OBJECT public: explicit GLWidget(QWidget *parent = nullptr); protected: void initializeGL() override; void resizeGL(int w, int h) override; void paintGL() override; private: QOpenGLShaderProgram m_program; QOpenGLTexture* m_texture; }; ``` #### 初始化资源与配置环境 在 `initializeGL()` 方法里完成必要的准备工作,比如编译链接顶点/片段着色器、启用深度测试等功能特性,并通过图像文件路径实例化 `QOpenGLTexture` 对象用于后续绑定操作: ```cpp void GLWidget::initializeGL() { // Initialize OpenGL functions and set up the rendering context. initializeOpenGLFunctions(); // Load vertex shader source code into a string variable... QString vsrc = "#version 330\n" "in vec2 qt_Vertex;\n" "out vec2 coord;\n" "void main() {\n" "coord = (qt_Vertex + vec2(1.0)) / 2.0;" "gl_Position = vec4(qt_Vertex, 0.0, 1.0);\n" "}\n"; // Similarly load fragment shader source code... if (!m_program.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vsrc)) close(); if (!m_program.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, "/* Fragment Shader Code Here */")) close(); m_program.bind(); // Create texture object from image file on disk or resource system. m_texture = new QOpenGLTexture(QImage(":/images/mytexture.png").mirrored()); } ``` #### 定义绘图过程 最后一步是在 `paintGL()` 函数内部编写具体的图形管线指令序列,这包括但不限于激活所需的缓冲区对象、传递变换矩阵给 GPU 端存储位置参数等动作;当然还有最重要的——调用 API 将之前准备好的二维数组形式的数据贴附至几何体表面之上形成视觉效果上的“材质”。 ```cpp void GLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLfloat vertices[] = { /* Define your geometry here */ }; GLuint indices[] = { /* Index buffer data goes here */ }; glVertexAttribPointer(m_program.attributeLocation("qt_Vertex"), 2, GL_FLOAT, GL_FALSE, 0, vertices); glEnableVertexAttribArray(0); m_texture->bind(); // Bind our previously created texture. glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLuint), GL_UNSIGNED_INT, indices); } ``` 以上就是关于怎样利用 Qt 框架下的 OpenGL 支持来进行基本的纹理映射工作的介绍[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值