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.

  • You say yourself about creating component from a string with `Qt.createQmlObject(string)`. So what is your question? – folibis Dec 03 '14 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. –  Dec 03 '14 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. – Mitch Dec 03 '14 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 http://stackoverflow.com/questions/27315030/how-to-manage-lifetime-of-dynamically-allocated-qobject-returned-to-qml –  Dec 05 '14 at 14:51
  • Posted an answer. By the way, there is a suggestion to add this to Qt here: https://bugreports.qt.io/browse/QTBUG-26278 – Mitch Nov 19 '21 at 18:21

2 Answers2

1

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; });
Mitch
  • 23,716
  • 9
  • 83
  • 122
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);
    }
}
folibis
  • 12,048
  • 6
  • 54
  • 97
  • 1
    I need to create a component from the string, not an object. –  Dec 03 '14 at 12:16
  • 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` –  Dec 03 '14 at 12:45