Dmitry Katkevich
Dmitry Katkevich

Reputation: 923

QML component isn't displayed if it was created programmatically from C++

My goal is to create a custom Component (lets call it ComponentLoader) which can instantiate another component (lets call it DelegateComponent) via delegate.

The problem is that the instance of DelegateComponent isn't displayed after is was created (white screen). Note: tst_component is loaded message IS present which means that DelegateComponent instance was actually created.

Here is a minimal example:

main.qml

ApplicationWindow {
    id: mainWindow
    width: 640
    height: 480
    visible: true

    Component {
        id: tst_component

        Rectangle {
            anchors.fill: parent

            Component.onCompleted: {
                console.debug("tst_component is loaded");
            }

            Label {
                text: "hello world"
                anchors.centerIn: parent
            }
        }
    }

// doesn't work
    ComponentLoader {
        anchors.fill: parent
        delegate: tst_component
    }

// works
//    Loader {
//        anchors.fill: parent
//        sourceComponent: tst_component
//    }
}

componentloader.h + componentloader.cpp

#pragma once
#include <QQuickItem>

class ComponentLoader : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)

public:
    QQmlComponent* delegate() const;
    void setDelegate(QQmlComponent*);

signals:
    void delegateChanged();

private:
    void generate();

protected:
    void componentComplete() override;

private:
    QQmlComponent* mDelegate = nullptr;
};

// componentloader.cpp
#include "componentloader.h"
#include <QtWidgets/QtWidgets>
#include <QtQmlModels/QtQmlModels>
#include <QQuickWindow>

QQmlComponent* ComponentLoader::delegate() const
{
    return mDelegate;
}

void ComponentLoader::setDelegate(QQmlComponent* delegate)
{
    if (delegate != mDelegate)
    {
        mDelegate = delegate;
        emit delegateChanged();
    }
}

void ComponentLoader::componentComplete()
{
    QQuickItem::componentComplete();
    generate();
}

void ComponentLoader::generate()
{
    QQmlEngine* engine = qmlEngine(this);
    QQmlContext* root_ctx = engine->rootContext();
    QQmlContext* ctx = new QQmlContext(root_ctx);

    QObject* item = mDelegate->create(ctx);
    QQuickItem* quickItem = qobject_cast<QQuickItem*>(item);

    QQuickItem* quickParent = qobject_cast<QQuickItem*>(parent());
    quickItem->setParent(quickParent);
    quickItem->setParentItem(quickParent);
}

Upvotes: 0

Views: 144

Answers (1)

JarMan
JarMan

Reputation: 8277

Your quickParent pointer is taking the QObject parent() value instead of the QQuickItem parentItem() value.

Simply changing it to this worked for me when I tried your code:

QQuickItem* quickParent = qobject_cast<QQuickItem*>(parentItem());

I also don't think you need to call setParent() at all. Just setParentItem().

Upvotes: 1

Related Questions