Tuesday 6 August 2013

Alpha 2: Passing simple C++ properties from main.cpp to the QML Side with Qt5

One of the first challenges in migrating LandedSettings from the Sailfish Alpha 1 7 Qtt to Alpha 2 / Qt5 was that I pass a simple property from the main.cpp file (C++) to the QML side via a setContextProperty call.

The property was platform, and was intended to allow the Qml side to change font size etc according to the platform it was running on. I originally added this functionality to handle differences between the Nokia Simulator and the Haramattan Emulator (QEMU).

In Qt4 I was able to pass such properties via a call to setContextProperty, offered by a bit of Nokia code called the QmlApplicationViewer. As this is no longer included with the Sailfish Alpha 2, and will not run unchanged, I needed to migrate this to something different. As we will see their were a number of approaches I could have taken.



Qt 4 Style using QmlApplicationViewer

Below is an extract from my Qt4 main.cpp file.


#include "qmlapplicationviewer.h"

 

Q_DECL_EXPORT int main(int argc, char *argv[])

{

    //Some C++ code here to determine the platform and set an int platformId

    QScopedPointer<QApplication> app(createApplication(argc, argv));

 

    QmlApplicationViewer viewer;

    viewer.rootContext()->setContextProperty("platform",  platformId);

    viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);

    viewer.setMainQmlFile(QLatin1String("qml/landedsettings21/main.qml"));

    viewer.showExpanded();

 

    returnapp->exec();

}

Having set a variable platform of type int, I could then pass it to QML via the setContextProperty call in red above. This exposed a property "platform" that could be used anywhere in my QML.

So what where the options to migrate this to Qt5, and which did I chose? I found 3, and chose the last of these.

Keep the QmlApplicationViewerCode, Migrate it to Qt5

In theory I could have copied the QmlApplicationViewer code files from a Harmattan project, and migrated these to Qt5.

This technique is suggested in a porting tutorial from the Qt Project, but somehow this seemed like carting old baggage around with me.

Use qmlRegisterXXXType

This is a valuable technique I have used elsewhere (e.g. AbstractUI, Landed) to C++ / QML interaction. I use this for exposing C++ objects with properties, methods, signals etc. that can be manipulated by QML.

To use this technique I would need to create one or more classes in C++, and to use it QML include an "import" statement in each QML file that wanted to access the property. This all seems a bit much given that "platform" is a primitive type (and could even have been a string literal).

So while this would be a valid approach, I decided to keep this as a backup option, and see if I could find a more direct equivalent of the setContextProperty. However I plan to look at this technique in more detail in a future post.

setContextProperty the Qt5 Way

After some experimentation, and with suggestions from the Sailfish Developers Mailing List, I arrived at a solution that is close to the Qt 4 setContextProperty solution, but does not require the QmlApplicationViewer code.:

Q_DECL_EXPORT int main(int argc, char *argv[])

{

  

    //Some C++ code here to determine the platform and set an int platformId

    QScopedPointer<QGuiApplication> app(Sailfish::createApplication(argc, argv));

   

    QScopedPointer<QQuickViewview(Sailfish::createView());

   

    view->rootContext()->setContextProperty("platform",  platformId);

    Sailfish::setView(view.data(), "main.qml");

 

    Sailfish::showView(view.data());

    

    return app->exec();

}

 

Compare this to standard main function as generated for a default new Sailfish project below:

 

Q_DECL_EXPORT int main(int argc, char *argv[])

{

    QScopedPointer<QGuiApplication> app(Sailfish::createApplication(argc, argv));

   

    QScopedPointer<QQuickView>view(Sailfish::createView("main.qml"));

    

    Sailfish::showView(view.data());

    

    returnapp->exec();

}

 

In my solution, the createview function is called without specifying the main.qml, we do this two lines later with the setView function. In between we can then do the setContextProperty.

 

Note for this to work properly, a bug-fix has to be applied to the sailfish application.cpp file, Thanks to Lucien XU for this. You can find his post here.


Example Code Posted to GitHub

 

I have created a throwaway demo setContextPropertyDemo that illustrates this technique. You can find the code here.

No comments:

Post a Comment