7

I have spend 3 days carefully checking the best reference material I could find on internet about Q_RETURN_ARG. I have already included QQmlComponent. When using it on C++ to send a variable to display on QML, things are not always as they seems. Maybe because Qt5 is relatively new, there is not much material put together that we can rely on yet.

Basically, the code compiles without problem. When I ask it to run, it renders the qml page to the device with no problem, and then it gets the error:

QQmlComponent: Component is not ready
main.cpp:33 (int main(int, char**)): Got QML return: ""

Besides the files invoke.pro and myapplication.cpp, here are the key parts of the small example I am trying to work out, based on this post, Qt5 documentation,ICS tutorial, post, and link:

./myapplication.h

#include <QObject>
#include <QDebug>
#include <QQmlComponent>

class MyApplication : public QObject
{   Q_OBJECT
    public:
        explicit MyApplication(QObject *parent = 0);
        ~MyApplication(void) {}    
        QObject *object;
        QQmlComponent *component;

        void loadComponent(void)
        {   QQmlEngine engine;
            QQmlComponent *component = new QQmlComponent(&engine);
            component->loadUrl(QStringLiteral("qml/invoke/main.qml"));

            if(!component->isReady()){
                qWarning("qPrintable: %s", qPrintable(component->errorString()));
            }

            if (component->isLoading()){
                cout <<"==== component->isLoading ====";
                QObject::connect(component,
                                 SIGNAL(statusChanged()),
                                 this,
                                 SLOT(continueLoading()));
            }
            else{
                cout <<"==== component is not Loading ====";
                continueLoading();
            }
        }    
    signals:

    public slots:
        void continueLoading()
        {   QQmlEngine engine;
            QQmlComponent *component = new QQmlComponent(&engine);
            component->loadUrl(QStringLiteral("qml/invoke/main.qml"));

            if (component->isError()) {
                qWarning() << "component->isError()="<< component->errors();
            } else {
                object = component->create();
                cout <<"object created";
            }
        }    
};

./main.qml

import QtQuick 2.0
Rectangle {
    width: 360
   height: 360
    Item {
        function myQmlFunction(msg_cpp) {
            console.log("Got msg_cpp:", msg_cpp)
            return "output"
        }
    }
}

./main.cpp

#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QtQuick/QQuickItem>
#include <QtQuick/QQuickView>
#include <QQmlEngine>
#include <QtQml>
#include <QDeclarativeEngine>
#include <QtCore>
#include <QtQuick/QtQuick>
#include <QQmlComponent>
#include <QtQml/qqml.h>
#include "myapplication.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/invoke/main.qml"));

    MyApplication *myClass = new MyApplication();
    myClass->loadComponent();

    QObject *object=myClass->object;

    QVariant returnedValue;
    QVariant msg_cpp = "C++ message";
    QMetaObject::invokeMethod(object,
                              "myQmlFunction",
                              Q_RETURN_ARG(QVariant, returnedValue),
                              Q_ARG(QVariant, msg_cpp));
    qDebug() << "Got QML return:" << returnedValue.toString();

    viewer.showExpanded();
    delete object;
    return app.exec();
}

Which gives the error:

loadComponent()): qPrintable: file://qml/invoke/main.qml:-1 File not found
continueLoading()): component->isError()= (file://qml/invoke/main.qml: File not found) 
main.cpp:36 (int main(int, char**)): Got QML return: "" 

I noticed that main.qml is meant to load on Android using "QtQuick2ApplicationViewer" instead of "QQmlEngine". Should the "QQmlEngine" not be used at all for loading main.qml in attempt to get Q_RETURN_ARG running - when dealing with Android, and therefore that is why "QQmlComponent component" is not loading? If I try to use " QtQuick2ApplicationViewer viewer" replacing "QQmlEngine engine" for "QQmlComponent component", it says: "no matchning function for call to QQmlComponent".

Any suggestions how to get QQmlComponent initialized, so Q_RETURN_ARG starts working? Thanks!

Community
  • 1
  • 1
Gerry Woodberg
  • 336
  • 1
  • 11
  • 1
    Why are you not using the statusChanged signal and connect? I think you failed to copy and paste the example over from the Qt documentation for starter. – László Papp Jan 09 '14 at 03:21
  • just added the suggestion and additional review. – Gerry Woodberg Jan 09 '14 at 07:14
  • 1
    You have two issues. You are missing the closing bracket after the signal. You are not passing the "QQmlComponent::Status" argument type to the signal, nor the slots. – László Papp Jan 09 '14 at 08:05
  • thanks. you are right about the bracket. the signal and slots are sent as you can see in the update. the main.qml is still not found. – Gerry Woodberg Jan 09 '14 at 08:54

1 Answers1

7

I got a quick review of your code and got it working with a few changes, but it has some big(BIG!) QT/coding concepts missing.

Some of the key errors to get it working:

  • File error is just a matter of setting the file path properly.
  • Loading source needs time, not an eager sequence of not ready -> load again with other QQmlEngine. (this is not fixed in my code)
  • myQmlFunction needs to get upper in QML tree, or some other kind of reference help.
  • ...

Here you can take a look at full code.

http://pastebin.com/PRLBtKWU

I would recommend you to take a look at this book http://qmlbook.org/ and to practice with QT examples for your current QT version.

kikeenrique
  • 2,589
  • 2
  • 25
  • 46
  • Thanks! I really appreciate your feedback. Today I got the chance to try your example. I followed the exact same steps reusing the same edited code you posted. From line 66 I got the error: ./qt5app/myobject.cpp:4: error: 'myobject' does not name a type myobject::myobject(QObject *parent) : :-1: error: [myobject.o] Error 1. Any suggestion? – Gerry Woodberg Feb 15 '14 at 23:42
  • 1
    May it be a case sensitive error? myobject must be MyObject in c++ code, but files are named myobject. – kikeenrique Feb 17 '14 at 09:23
  • Thanks again - you were right about the uppercase MyObject solved it. Now at line 77, I got this other error: ./qt5app/myobject.cpp:15 (void MyObject::loadComponent()): qPrintable: file:///data/data/org.qtproject.example.qt5app/files/qml/qt5app/main.qml:-1 File not found. Any suggestion? – Gerry Woodberg Feb 17 '14 at 10:02
  • 1
    Missing qml file, I've pasted it in pastebin. – kikeenrique Feb 17 '14 at 13:20
  • The same error remains "main.qml:-1 File not found". But if I comment out the code from line 138 to 152 and 155, then the code runs and the main.qml loads in the device. Any suggestion? – Gerry Woodberg Feb 19 '14 at 05:30
  • 1
    It must be a paths problem, I've updated pastebin with my directory tree. – kikeenrique Feb 20 '14 at 13:48
  • Just to know... I wonder if you are running the example in cross-compile mode - e.g. host pc & target Android device? Checking your directory tree I see "desktop". How did you created your project? Have you on Qt Creator made the option: [ File > New Project > Applications > Qt QUick Application ] ? Other projects I am running QML and C++ without using the invokeMethod are working with no problem. – Gerry Woodberg Feb 26 '14 at 23:57