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. Calling QML functions from C++ [SOLVED]
Forum Updated to NodeBB v4.3 + New Features

Calling QML functions from C++ [SOLVED]

Scheduled Pinned Locked Moved QML and Qt Quick
12 Posts 2 Posters 11.0k Views 1 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.
  • N Offline
    N Offline
    Neon_Burg
    wrote on last edited by
    #1

    I need to send/insert string value to the qml TextArea conmponent, from c++. I decided to use qml function, which would recieve the string value and then insert it to the TextArea.insert(). But when i do it, my application suddenly closes...

    qml function code:
    @function insertText(QString, msg) {
    textArea.insert(msg);
    }@

    C++ code:
    @QString msg = "Hello from C++";
    QMetaObject::invokeMethod(object, "insertText",
    Q_ARG(QString, msg));@

    Final goal is to read file by c++ fstream library into QString and show it content on the application screen. Help me with solution!

    1 Reply Last reply
    0
    • U Offline
      U Offline
      utcenter
      wrote on last edited by
      #2

      Try something like this:

      @// in this case this is the root QML object
      function foo(msg) {
      console.log(msg)
      }@

      And in C++

      @
      QMetaObject::invokeMethod(engine.rootObjects().at(0), "foo", Q_ARG(QVariant, QVariant::fromValue(QString("blabla"))));@

      In JS you don't have types in the function parameters, only identifier, so remove that QString, and BTW in QML it is string, not QString

      And in C++ you have to use a variant and pass the value in a QVariant.

      Also, the fact that your application "closes" signifies there is something wrong, for example, the object you pass to invokeMethod() is not valid. If that method fails to locate the function, you will only get an error in the console, but your app will continue running normally. So most likely your object is not valid.

      If the QML function is not in the root element, set its objectName property to someText and use the root item's findChild() method to find the child with the someText name, check if it is indeed found and only then use it in invokeMethod()

      @QObject * object = engine.rootObjects().at(0)->findChild<QObject*>("someText");@

      1 Reply Last reply
      0
      • N Offline
        N Offline
        Neon_Burg
        wrote on last edited by
        #3

        The first way gave an error:

        ASSERT failure in QList<T>::at: "index out of range"

        I try to do it like this:

        @QObject * object = engine.rootObjects().value(0)->findChild<QObject*>("algoShow");
        QMetaObject::invokeMethod(object, "insertText",
        Q_ARG(QVariant, QVariant::fromValue(QString("Hello from c++!"))));@

        or like this:

        @QObject * object = engine.findChild<QObject*>("algoShow");@

        and QML:

        @function insertText(msg) {
        console.log(msg);
        }@

        But nothing happened, i think that function was not invoked..

        1 Reply Last reply
        0
        • U Offline
          U Offline
          utcenter
          wrote on last edited by
          #4

          bq. ASSERT failure in QList<T>::at: “index out of range”

          Do you have any QML created at the time you try that? If you don't have the first element in root objects, then you probably don't have anything at all, you HAVE TO HAVE root before you can have anything else. You are probably doing it before any QML is loaded.

          The reason you don't get the out of range error with value() is because this method returns a default constructed value if nothing is found, so you get a null pointer, which is why invoke method doesn't do anything.

          Make sure you have your QML loaded before you try to access it.

          @engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); // or whatever your main QML file is@

          1 Reply Last reply
          0
          • N Offline
            N Offline
            Neon_Burg
            wrote on last edited by
            #5

            Oh, i loaded main,qml, right like you wrote. But then i also created two qml files directly from qml document, in this way:

            in main.cpp I load main.qml:

            @Manager manager;
            engine.load(QUrl(mainPath));
            object = engine.rootObjects().value(0);
            engine.rootContext()->setContextProperty("myObj", &manager);@

            in main.qml I load the second qml file :

            @ApplicationWindow {
            id: mainWindow
            property variant win;

            button {
            ...
            onClicked: {

                  var component = Qt.createComponent("qrc:/Smejnost.qml");
                  win = component.createObject(mainWindow);
                  win.show();
              }
            

            }}@

            Maybe you can suggest a better way, how to load and manage qml files. I'm just a beginner :)

            1 Reply Last reply
            0
            • N Offline
              N Offline
              Neon_Burg
              wrote on last edited by
              #6

              Actualy, this way has one big disadvantage.. I dont see any created qml windows, except the main,qml, when launching the project on android..

              1 Reply Last reply
              0
              • U Offline
                U Offline
                utcenter
                wrote on last edited by
                #7

                Well, you don't honestly expect that you will be able to find the object in C++ main() before it was created in QML, right?

                There is nothing wrong with the way you create the Smejnost component, and regardless of the style of creation, you will always need to have it created before you can locate it with findChild().

                You just have to put your call from C++ to QML in the proper "spot", not simply in main, because it will run immediately after the main component is set, before you have the chance to create extra components from QML.

                But if you really want to put it in main, you can use a signal, add a signal to the ApplicationWindow, in main() find the main object and connect that signal to a free function or lambda which wraps the findChild() and inkoveMethod() call, and from QML emit the signal when Smejnost has been created. This way you will attempt to find the target component only after it is created.

                1 Reply Last reply
                0
                • N Offline
                  N Offline
                  Neon_Burg
                  wrote on last edited by
                  #8

                  I load qml file, using

                  @engine.load(QUrl(QStringLiteral("qrc:/Algo_Show.qml")));
                  object = engine.rootObjects().at(0);@

                  it worked, but function is still not invoked.

                  Error:

                  QMetaObject::invokeMethod: No such method QThread::insertText(QVariant)

                  1 Reply Last reply
                  0
                  • N Offline
                    N Offline
                    Neon_Burg
                    wrote on last edited by
                    #9

                    YES ! I just load qml file like in qt tutorial, and it's worked !

                    @QQmlEngine engine;
                    QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:/Algo_Show.qml")));
                    QObject *object = component.create();
                    QVariant msg = "Hello from C++";
                    QMetaObject::invokeMethod(object, "insertText",
                    Q_ARG(QVariant, msg));
                    @

                    Like i said before, i'm just a begginer ) But the problem solved! Thanks.

                    1 Reply Last reply
                    0
                    • U Offline
                      U Offline
                      utcenter
                      wrote on last edited by
                      #10

                      Yes, you could have created the QML object from C++ as well. All this is for the sake of getting a test to work I guess, you will have to figure out how to lay out your actual application so you avoid the "chicken or egg" paradox.

                      And since you already use Qt, you might as well be using QFile instead of fstream.

                      1 Reply Last reply
                      0
                      • N Offline
                        N Offline
                        Neon_Burg
                        wrote on last edited by
                        #11

                        I got a new paradox, qml file was open, but i cant click at any button or qml object.. Like it's not active.

                        1 Reply Last reply
                        0
                        • N Offline
                          N Offline
                          Neon_Burg
                          wrote on last edited by
                          #12

                          Problem is finaly solved!

                          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