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.