torstai 19. joulukuuta 2013

Huge performance boost by using qrc on Android

As mentioned here by using the Qt Resource System (qrc) has significant benefits over the assets folder on Android. Loading e.g. Qml-files is significantly faster with qrc than using assets.

Quite misleadingly the "Qt Quick Application" wizard on Qt Creator (3.0.0 and below) will currently use assets as the way to bundle files on Android. Instead I tried packaging all my Qml files, images and other static assets to qrc and my app loading times dropped from +5 seconds to a fraction of a second, so there really is a difference!

In addition the qrc system is cross-platform and there is a simple wizard in Qt Creator for creating the qrc-package.

maanantai 21. lokakuuta 2013

First hybrid app

I uploaded my first hybrid app made with Qt 5.1 to Google Play. The app is a simple score counter that can be used to track scores in social games like card e.g. card games. It uses C++/Qt for logic and QML for the UI.

Since Qt 5.1 for android is a developer preview version there are still many things that are not fully functional. This app was exclusively tested only on android 4.1 running on Samsung Galaxy Note II, so there's no guarantee that it will run on other setups. Qt 5.2 is promised to bring a performance boost and a more stable build on android, and Digia has encouraged to postpone app publishing in Play Store until then. That being said you are welcome to test the app and email me if you have any questions about it. If someone is interested in the source code, please do inform me and I'll see what I can do :)

torstai 17. lokakuuta 2013

Android package sign problem

So I ran into trouble when trying to publish my first Qt application on google Play store (using Qt 5.1.1, and Qt Creator 2.8.1). First of all I learned that "The Android system requires that all installed applications be digitally signed with a certificate whose private key is held by the application's developer" (more info here). Luckily Qt Creator 2.8.1 already includes an automated tool for creating this private keystore, so there's little extra effort involved. So I created a new keystore, signed my application with it and compiled the release version. But when I tried to deploy the app to my cellphone through Qt Creator, it would not start at all.

Turns out that the problem was that the default signing algorithm has changed between JDK 6 and JDK 7. So if you have JDK 7 installed your package will get signed with an unacceptable algorithm. More on this problem can be found here. My solution was to temporarily replace JDK 7 with JDK 6 (not the best solution). After this I could succesfully deploy the signed package.

tiistai 24. syyskuuta 2013

Multilayered architecture in hybrid applications

I suggest that everyone who is interested in C++/QML hybrid programming reads this blog post from David Johnson (ICS). The text illustrates how a multilayered architecture can be used to easily integrate the visual QML elements into C++ logic with the use of QObject adaptation layer.

I have used this kind of architecture in my own hybrid programs, and the main advantages are:

  • Separation between logic and UI (between C++/Qt and QML)
    • The application UI/UX (visual elements, animations, behaviors, multimedia, shaders, etc.) can be entirely created in QML and it is practically isolated from the C++/Qt logic. This enables the parallel and isolated creation of UI/UX and logic by e.g. different development teams.
  • Easy communication between QML and C++/Qt
    • The QObject adapter can handle communication between the logic and QML. This can be done via signals and slots (works both ways), or by accessing the functions provided by QQuickItems (works only when information flows from logic to QML).
  • Efficient data containers for accessing QQuickItems
    • The QQuickItems (i.e. QML Items) are stored in a tree hierarchy that can be difficult to manage in C++/Qt logic. The QObject adapters on the other hand can be stored in any arbitrary data container (hashes, maps, lists...) thus enabling efficient access to the QQuickItems from logic.

sunnuntai 14. heinäkuuta 2013

First thoughts on Qt and Android

After the release of Qt 5.1 we all now have the opportunity to run some Qt apps on an Android device. Some neat examples by Digia can be found on the Play-store (Qt 5 Everywhere and Introduction to Qt 5).

Even though this is a developer preview of Qt on Android/iOS the experience already feels quite good. The UI is very responsive and the OpenGL demos look awesome. One issue I've found so far is that loading custom Fonts with FontLoader doesn't work at this point. I'ts really weird because a custom font is nonetheless succesfully used on the Qt 5 Everywhere demo...

One word of warning for the C++ hybrid coders. When creating QQuickItems synchronously (not multithreaded) with the QQmlComponent class, there is a notable lag on a mobile device (even with a monster like Note II). Qt also offers an asynchronous method for creating QQuickItems but I've yet to master its usage (to my understanding the asynchronous method involves QQmlIncubators that create the QQuickItem on a separate thread to avoid freezes in the UI).

torstai 18. huhtikuuta 2013

Registering actions in all stacked MouseAreas

The qml MouseArea has a property called propagateComposedEvents that allows composed mouse actions like clicks to be registered in multiple MouseAreas. The following Qml-file demostrates it's use. The example based on Qt Quick 2 Application template provided by Qt Creator 2.7, and run on Qt 5.0.2.

import QtQuick 2.0

Rectangle {
    width: 360
    height: 360
    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
    Rectangle {
        color: "blue"
        anchors.fill: parent

        MouseArea {
            id: blueMouseArea
            anchors.fill: parent
            hoverEnabled: true
            onClicked: console.log("Blue Clicked");
            onPositionChanged: console.log("Blue Hovered");
        }
    }
    Rectangle {
        color: "red"
        anchors.top: parent.verticalCenter
        anchors.bottom: parent.bottom
        anchors.left: parent.horizontalCenter
        anchors.right: parent.right

        MouseArea {
            id: redMouseArea
            hoverEnabled: true
            anchors.fill: parent
            // Set propagateComposedEvents to true, and "mouse.accepted" to false
            // if you want composed events to be propagated to other MouseAreas that are below,
            // in this case to blueMouseArea. Composed event consists of more
            // basic events. Eg. a click consists of a pressed and a released event
            propagateComposedEvents: true
            onClicked:
            {
                console.log("Red Clicked")
                // Setting "mouse.accepted" to false has to be also done
                // in order for the event to propagate
                mouse.accepted = false
            }
            // Trying desperately to get hover events to propagate to blueMouseArea.
            // The documentation says that the accepted property of the MouseEvent
            // parameter is ignored in "onPositionChanged"-handler. I'm not sure what
            // that means though...
            onPositionChanged:
            {
                console.log("Red Hovered");
                mouse.accepted = false
            }
        }
    }
}

In this example I also try to unsuccesfully propagate hovering. This may be impossible or then I'm just missing something...

perjantai 15. maaliskuuta 2013

Porting Qt5 to mobile ecosystems

Qt is actively being ported to the two biggest (at the time) mobile ecosystems: Android and iOS. Here are two relevant blog posts from digia conserning this task: Android and iOS.

This promises very exciting times for all the Qt developers, as we are given an access to a huge audience. I think that Qt5 has all the ingredients for a major breakthrough as the best development platform for mobile devices. It's not just that we CAN now create sweet graphics, but because development is so FUN! (I'm referring to QML with the fun part).

keskiviikko 30. tammikuuta 2013

Searching and manipulating Items in a QML-file through C++/Qt logic

Say you would like to manipulate an Item you have declared in a QML-file through C++/Qt logic. This example is again based on the Qt Quick 2 Application template provided by Qt Creator 2.61, and run on Qt 5.0. We add a new Item (these are called QQuickItems in logic) to the main.qml file with the id "manipulatedItem", so that it looks something like this:

import QtQuick 2.0

Rectangle {
    width: 360
    height: 360
    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }
    Rectangle {
        id: notObjectName
        objectName: "manipulateMe"
        color: "blue"
        anchors.fill: parent
    }
}

Notice that we define the property "objectName" for this new Item. Now we can modify the added QML-item in main.cpp:

#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QQuickItem>                     // Notice this include

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

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

    // The findChild-method is used to locate the child object called "manipulateMe".
    // This searching is done recursively, so the whole "branch" is searched. Notice
    // that this searched name is NOT the id of the QML-item, but it is the property
    // called "objectName".
    QQuickItem * manipulatedQQuickItem = viewer.rootObject()->
            findChild<QQuickItem*>("manipulateMe");

    // Now we can manipulate the object through this pointer.
    // But what if the pointer becomes invalid?
    if (manipulatedQQuickItem)
    {
        manipulatedQQuickItem->setOpacity(0.5);
        manipulatedQQuickItem->setProperty("color","red");
    }
    viewer.showExpanded();
    return app.exec();
}

Now you can now modify the Item anyway you like. But there is a risk that the Item gets destroyed before you modify it. So as always you have to be careful with dangling pointers.

sunnuntai 27. tammikuuta 2013

Storing visual QML item (QQuickItems) in C++/Qt data models

Communication between C++ and QML is not always so trivial. Qt provides some very cool ways to pass variables and simple data models to QML by using Q_PROPERTIES and QAbstractItemModel or a more specific models inherited from this. But what if you have to pass more complex data models from C++ logic to QML? How to pass data stored in QMaps and QHashes for example? Atleast as far as I know (please enlighten me if I'm wrong about this) QAbstractItemModel-class can only provide data stored in lists/multidimensional lists/tree-like data models to QML.

The idea behind models is to create visual QML-delegates based on the data stored in the model. And when you change the data stored in the model, the QML-delegates also change accordingly. The problem is that there are no ready models for the more complex datatypes like hashes and logarithmic trees. And in my experience it's very nasty/impossible to try and subclass the QAbstractItemModel for arbitrary data models.

One way to go around this problem is to dump the models between your logic and QML. The trick is to create the visual QML-objects (objects derived from QQuickItem) in your C++ code and store pointers to them into the wanted arbitrary data structure. Then you also have to reparent these QQuickItems to the shown window. The danger here is that you now have a pointer to the QQuickItem in your data structure, but you have granted the ownership of the QQuickItem to the parent item. This can result in dangling pointers, so you have to be careful. To do this you have to break the barrier between logic and QML a bit more than is "recommended". See this page for more discussion on manipulating the QML object tree through C++ (search the word WARNING to find the right paragraph :P ).

Notice that there are two kind of parents for QQuickItems: visual parents and QObject-parents. When you reparent a QQuickItem to another QQuickItem item using the funtion QObject::setParent(), the ownership of the item is transferred to the parent. This ensures that the reparented item is destroyed when the parent is destroyed. On the other hand if you reparent an item using QQuickItem::setItemParent(), you reparent the item only visually. Data ownership is not transferred in this case.

Now follows an example that shows how to create QQuickItems from an QML-file, and visualise them in your view. This example is based on the Qt Quick 2 Application template provided by Qt Creator 2.61, and run on Qt 5.0. The following code is from the main.cpp file and I will explain it a bit more below.

#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QQmlComponent>                // Notice these includes
#include <QQuickItem>                   // Notice these includes
#include <QQmlEngine>                   // Notice these includes

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

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/untitled1/main.qml"));
    viewer.showExpanded();
    
    // This part is where we create the QQuickItem based on a QML-file
    QQmlComponent component(viewer.engine(),
                            QUrl::fromLocalFile("qml/untitled1/RedRect.qml"));
    QQuickItem *redRect = qobject_cast<QQuickItem *>(component.create());
    
    // Store the redRect anywhere you like for later access
    // You can later on modify the visual QQuickItem through this pointer
    // Here are some example functions for modification:
    //  -QObject::setProperty()
    //  -QQuickItem::setX()
    std::vector<QQuickItem *> dataStructure;
    dataStructure.push_back(redRect);
    
    // Here we reparent the created QQuickItem (first the traditional QObject
    // parenting and then the visual parenting).
    // WARNING: after this the ownership of redRect is transferred to the
    // rootObject (main.qml), but you also have a pointer to redRect in your
    // data structure. This is very dangerous because the pointer in the data
    // structure can become invalidated. You will have take this possibility
    // into account (use smart pointers or other methods to avoid this).
    redRect->setParent(viewer.rootObject());
    redRect->setParentItem(qobject_cast<QQuickItem *>(viewer.rootObject()));

    return app.exec();
}

As said this example is based on an template in Qt Creator 2.6.1, and you can create the template like this: File->New file or project->Projects->Applications->Qt Quick 2 Application (Built-in elements). In this example I've created a new QML-file called "RedRect.qml" to the project and it simply is a red rectangle (duh).

The "viewer"-variable is basically the main window that shows everything. In this case it is inherited from QQuickView, and thus it is assigned a root object that is defined in the "main.qml". To create a QQuickItem from a QML-file we first create a QQmlComponent. This class is the middle man in creating QQuickItems dynamically. This Component-class has a method called create(), that returns the RedRect as a QObject* so we cast it into an QQuickItem* and call it redRect. Then we store this pointer to the wanted data structure for further access. You can modify the created item through this pointer. The final step is to reparent the created QQuickItem to the view for visualisation and data ownership.

Feel free to comment, and tell me when I'm wrong about something in this entry. I will then update the text accordingly.

perjantai 25. tammikuuta 2013

First post

Testing out the syntax highlighter. Instructions for how to enable syntax highlighting in blogger are found at: http://www.cyberack.com/2007/07/adding-syntax-highlighter-to-blogger.html. Notice that syntax highlighting doesn't work (atleast for me) in dynamic views...

You have to escape the special HTML-characters in the source code. You can use this site to do it automagically.

void SayHello()
{
 std::cout << "Hello World!" << std::endl;
}