6

It is possible to create QML components from files using Qt.createComponent(filename)

It is possible to create QML object from strings using Qt.createQmlObject(string)

It is possible to create QML components from code via Component {...}

But is it possible to create a QML component from a string? I mean without going thorugh the effort of saving it as a temp file just for the sake of using Qt.createComponent(filename)?

EDIT: Just to clarify, I already have the components in this example form:

import QtQuick 2.0

Rectangle {
     width: 100
     height: 100
     color: "red"
}

So I need to create a component from that string without instantiating it. I can't simply wrap the string in a "Component {" + string + "}" because imports can not be declared inside a component. One solution would be to use complex parsing to insert the component just before the first element and after the imports, but it doesn't strike me as the most elegant solution to go about.

5
  • You say yourself about creating component from a string with Qt.createQmlObject(string). So what is your question? Commented Dec 3, 2014 at 11:57
  • 1
    @folibis - nope, check that again, I say "QML object" which is not the same as a "QML component", the component is a prototype for an object, but you cannot use an object in a place that requires a component. Commented Dec 3, 2014 at 12:03
  • 4
    If you don't mind using C++, you might be able to create your own kind of Component that uses QQmlComponent internally, as that class has a setData() function. You could expose this custom Component class to QML that forwards the call to setData(), or create the data property as a string. Commented Dec 3, 2014 at 21:13
  • @Mitch - this did work, you should have posted it as an answer. However, it raises another issue - how to manage the lifetime of the component automatically stackoverflow.com/questions/27315030/… Commented Dec 5, 2014 at 14:51
  • Posted an answer. By the way, there is a suggestion to add this to Qt here: bugreports.qt.io/browse/QTBUG-26278 Commented Nov 19, 2021 at 18:21

2 Answers 2

2

Almost 7 years later I've run into the need to do this myself, so I thought I'd elaborate on the comment I left on the question.

For my use case, a singleton does a better job. You can use it in QML like this:

import MyModule 1.0

// ...

Loader {
    sourceComponent: QmlComponentCreator.createComponent("import QtQuick 2.0; Item {}")
}

The C++ implementation is below.

QmlComponentCreator.h:

#ifndef QMLCOMPONENTCREATOR_H
#define QMLCOMPONENTCREATOR_H

#include <QObject>
#include <QQmlComponent>

class QmlComponentCreator : public QObject
{
    Q_OBJECT

public:
    QmlComponentCreator() = default;

    Q_INVOKABLE QQmlComponent *createComponent(const QByteArray &data) const;
};

#endif // QMLCOMPONENTCREATOR_H

QmlComponentCreator.cpp:

#include "QmlComponentCreator.h"

#include <QtQml>

QQmlComponent *QmlComponentCreator::createComponent(const QByteArray &data)
{
    QQmlComponent *component = new QQmlComponent(qmlEngine(this));
    QQmlEngine::setObjectOwnership(component, QQmlEngine::JavaScriptOwnership);
    component->setData(data, QUrl());
    if (component->isError())
        qmlWarning(this) << "Failed to create component from the following data string:\n" << data;
    return component;
}

Somewhere in main.cpp, or wherever you register your types:

qmlRegisterSingletonType<QmlComponentCreator>("MyModule", 1, 0, "QmlComponentCreator",
    [](QQmlEngine *, QJSEngine *) { return new QmlComponentCreator; });
Sign up to request clarification or add additional context in comments.

Comments

0

use Qt.createQmlObject(string). It creates an object, not prototype.

Window {
    id: mainWindow
    visible: true
    width: 600
    height: 400
    Component.onCompleted: {
        var str = '
        import QtQuick 2.3;
        Component {
            Text {
                text: "Hello, world!";
                anchors.fill: parent;
                horizontalAlignment: Text.AlignHCenter;
                verticalAlignment: Text.AlignVCenter;
            }
        }';
        var component = Qt.createQmlObject(str,mainWindow);
        var object = component.createObject(mainWindow);
    }
}

2 Comments

I need to create a component from the string, not an object.
The problem is I already have the component strings with imports, but without a wrapping Component. I can't prepend Component { and append } because this breaks the code, imports can't be done in a Component

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.