Solved Can you create QML from a string/byte array?
-
I am trying to create run-time dynamically created QML content for use in a QQuickView or QQmlApplicationEngine.
I am doing this because I am writing a host application that users will be able to extend with their own QML extension plugins. I will not know the names of these components so there's no way for me to create a *.qml file that references their components.
I have been able to dynamically discover, load, and register their types currently (and am able to supply a base URI for these plugins when registering) - but I have to be able to instantiate their components and add them to my base 'host' QML (or replace that QML entirely with theirs.)
I am at a loss as how to do this.
I was hoping I could query the plugin for the names it registers and then programmatically generate QML that imports the correct components.
Suggestions? Thanks :)
-
-
Doesn't that require me to have my C++ code call into JavaScript in my host QML and then have the JavaScript call into Qt and on the C++ again - create QML components?
Surely there's a way to access the same Qt functionality that "Qt.createQmlObject" uses from C++ (and thereby avoiding the call into JavaScript and then the call back out into C++)?
-
Oh, I see. I thought you wanted to do this from the QtQuick side. You can do this from C++ like this:
QQmlEngine engine; QQmlComponent component(&engine); component.setData("import QtQuick 2.4\nText { text: \"Hello world!\" }", QUrl()); QQuickItem *item = qobject_cast<QQuickItem *>(component.create()); // add item to view, etc ...
See also: QQmlEngine, QQmlComponent.
-
Too simple... Just kidding! lol. Thanks :)
-
@Wieland Sorry to bother you because this is probably a very simple answer but I'm beating my head against the wall over this.
I'm trying to create a very simple test of what you mentioned above, but I cannot get the text to show up in my main window. My sample code is a simple QGuiApplication.
I have a method (shown below) that loads a very simple QML file, creates the component you wrote above, and tries to add it to the Window from the QML file.
void loadUI( QQmlApplicationEngine* in_pEngine ) { Q_ASSERT( in_pEngine != NULL ); // Load the main.qml which contains only a "Window" Qml component in_pEngine->load( QUrl(QStringLiteral("qrc:/main.qml")) ); // Let's create a trivial component and try to add that to the Window QQmlComponent l_oComponent( in_pEngine ); l_oComponent.setData("import QtQuick 2.4\nText { text: \"Hello world!\" }", QUrl()); QObject* l_pObject = l_oComponent.create(); Q_ASSERT( l_pObject != NULL ); QQuickItem* l_pItem = qobject_cast<QQuickItem*>( l_pObject ); Q_ASSERT( l_pItem != NULL ); // How to add our new component to the Window? l_pItem->setParentItem( qobject_cast<QQuickItem*>( in_pEngine->rootObjects().first() ) ); }
The empty window shows up just fine, and the text component creates just fine as far as I can tell, but I can never see it.
How should I be adding new components to an existing QML window?
I did validate that in_pEngine->rootObjects().first() has the object name of the Window I have in my QML file...
Thanks!
-
Your code is ok, the problem lies in a dark secret of
QtQuick.Window
. Have a look at the following snippet:Window { id: myWindow width: 800 height: 600 visible: true Rectangle { id: myRect color: "orange" anchors.fill: parent // This doesn't work with Window ! } }
Here
myWindow
is the parent ofmyRect
but it is not its parentItem (aka visual parent). This is a speciality ofWindow
. For stuff likeItem
,Rectangle
, etc, parent and parentItem are always the same. ForWindow
the parentItem iscontentItem
. So the following code is correct:Window { id: myWindow width: 800 height: 600 visible: true Rectangle { id: myRect color: "orange" anchors.fill: contentItem // This works ! } }
With this in mind it should be easy to understand why the following does what you want:
main.qml
import QtQuick 2.5 import QtQuick.Window 2.2 Window { width: 800 height: 600 visible: true Rectangle { id: myContent objectName: "myContentObject" // Needed for findChild() in C++ anchors.fill: contentItem color: "orange" } }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQuickItem> #include <QQmlContext> #include <QDebug> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); QQmlComponent component(&engine); component.setData("import QtQuick 2.4\nRectangle{color:\"black\";width:100;height:100}", QUrl()); QQuickItem *item = qobject_cast<QQuickItem *>(component.create()); QObject * rootObject = engine.rootObjects().at(0); QObject * targetItem = rootObject->findChild<QObject*>("myContentObject"); item->setParentItem( qobject_cast<QQuickItem *>(targetItem) ); return app.exec(); }
Hope it helps!
-
Bingo! Thanks! I'll note this carefully so I don't ever run into this again ;).
Cheers.