Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Can you create QML from a string/byte array?
Forum Updated to NodeBB v4.3 + New Features

Can you create QML from a string/byte array?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
8 Posts 2 Posters 4.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V Offline
    V Offline
    VRHans
    wrote on last edited by
    #1

    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 :)

    1 Reply Last reply
    0
    • ? Offline
      ? Offline
      A Former User
      wrote on last edited by
      #2

      Hi! Yes, it's easy: http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html#creating-an-object-from-a-string-of-qml

      1 Reply Last reply
      0
      • V Offline
        V Offline
        VRHans
        wrote on last edited by
        #3

        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++)?

        1 Reply Last reply
        0
        • ? Offline
          ? Offline
          A Former User
          wrote on last edited by
          #4

          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.

          V 1 Reply Last reply
          1
          • V Offline
            V Offline
            VRHans
            wrote on last edited by
            #5

            Too simple... Just kidding! lol. Thanks :)

            1 Reply Last reply
            0
            • ? A Former User

              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.

              V Offline
              V Offline
              VRHans
              wrote on last edited by
              #6

              @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!

              1 Reply Last reply
              0
              • ? Offline
                ? Offline
                A Former User
                wrote on last edited by A Former User
                #7

                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 of myRect but it is not its parentItem (aka visual parent). This is a speciality of Window. For stuff like Item, Rectangle, etc, parent and parentItem are always the same. For Window the parentItem is contentItem. 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!

                1 Reply Last reply
                0
                • V Offline
                  V Offline
                  VRHans
                  wrote on last edited by
                  #8

                  Bingo! Thanks! I'll note this carefully so I don't ever run into this again ;).

                  Cheers.

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved