Eine kleine view framework with QtQuick – Finale

Allrighty. In the last two posts (here and here) we laid the foundations for a rudimentary QML view framework. This time we add some simple context sensitivity to the UI and finalize the amazing KittyApp. Oh yeah, about that neat performance trick I promised in the first post – well I’m breaking my promise. I’ll write about it in a separate post.

The context sensitive parts of our UI will be the title bar (the text on the top of the screen) and the highlight feature in the navigation buttons. We will be implementing it the declarative way(TM), so that the context sensitive UI elements will be automatically updated when the view is switched. Similar functionality could of course be achieved by imperative means (i.e. running javascript code to set properties of the context sensitive elements during view switching), but I think this is nicer, although we still need to run just a little bit of javascript to work around a small nuisance.

Something about bindings (pros can skip this)

In order to change the title text whenever the active view changes, we will use a QML mechanism called binding. In case you’re new to QML a brief explanation: binding is a mechanism of QML that allows you to define a value of a property using another property or properties and combine them with javascript expressions. The simplest case is of course: “a.foo: b.bar”, but it could also be something much more complex like “a.foo: c.selected ? b.bar + d.fubar : e.width * 0.2″. A very nice feature (well it wouldn’t really be a binding without this) of binding is that it automatically updates it’s value when one of the factors in the expression changes. This is made possible by Qt’s signals and slots mechanism. All the dirty details of connecting the right signals and re-evaluating expressions is naturally taken care of for you by the declarative engine.

Beware though, they still are javascript expressions (Correct me if I’m wrong but even the simplest form of binding (assigning another property (what is it with me and these nested parentheses? (Seriously!?))) is still an javascript expression.  That’s unless the good folks at Qt have implemented an optimization for this special case. Facts, anyone?), which means that they are poison to fluid animation. If you’re (of course you are) targeting 60fps animation you have only 16,66666ms to spend per frame and you don’t want waste any more than the absolute minimum of that to running javascript. So remember to check your bindings to make sure you’re not binding to some property (directly or indirectly via another binding) that gets animated. If you’re targeting desktop things might be different, but there’s never enough processing power on a mobile device.

An example of avoiding unnecessary bindings: you have two images you want to place next to each other with some margin. It’s very tempting to bind the x properties like this [imageB].x: imageA.x + imageA.width + 20. The right way to do it of course is to use anchors. Anchors have an explicit meaning and  the x, y, width and height properties can be calculated quickly without the use of javascript. No matter how sick you are repeating the setting the anchors mantra in your QML, don’t cut corners. It’s retarded.

Back to the subject at hand

So let’s add some context sensitivity. First up the navigation buttons. Here are the relevant bits inside NavigationButton.qml:

And this is how they’re instantiated:

The buttons have an active property which dictates the cosmetics of the button and when we instantiate the buttons we bind the active property to a javascript expression viewSwitcher.currentView == <reference to a view>. That’s it. Pretty simple, huh?

Switching the view title works in a similar way, but there’s a catch. Let’s see the code first:

To support both normal  views and ViewLoader (if you don’t remember what this was about, go read the previous post) views, the properties that contribute to the context need to be bound to the properties of the loaded views. Like this:

So the text property is bound to the currently active view’s viewTitle property – couldn’t be simpler. The small complication is caused by our use of ViewLoader. Binding directly to the item property of the loader causes the declarative engine to print warnings during construction of the ViewLoaders and unloading of the views (remember the keepLoaded property). This is because before loading and after unloading the item property is null and thus doesn’t have the viewTitle property and declarative engine spits out a warning about it. Now this doesn’t have any adverse effects on the functionality, but it’s pretty annoying to have a buttload (amount of properties * amount of loadable views = buttload) of warnings when you start up and then some more when ever you switch away from a view that won’t be kept loaded. All the useful logging plus real warnings and errors get buried in the mess.

We can work around the problem by making the binding a simple javascript expression that makes the property bind to some benign default value. Like this:

Problem solved (let me know if you find a better way to solve this). I’m not saying you have to do this. It all depends how pedantic and annoyed by warnings you are. If you often find yourself organizing the icons on your desktop or unmatched HTML tags give you hives and emotional discomfort, you probably have to do it.

Wrap up

Here’s the code (BTW the kitty, the sheep and the rainbow are shamelessly taken from openclipart.org – I assume it’s ok) and here’s the sis file you can install to your Symbian (preferably S^3) device. Before you can run it, you need to install the Qt which ships with the QtSDK 1.1 TP. Note that for some reason the damn font files won’t unload. Luckily this whole font mess is solved in the upcoming Qt 4.7.2 release). So for now you need to reboot after running KittyApp, if you want uninstall it (can’t figure out why someone would want to do that though).

This entry was posted in Programming and tagged , , , , , , , . Bookmark the permalink.

3 Responses to Eine kleine view framework with QtQuick – Finale

  1. Pingback: Tweets that mention Eine kleine view framework – Finale | Blogasdf -- Topsy.com

  2. Hi,

    Two small problems:

    main.cpp:2:30: fatal error: QDeclarativeView.h: No such file or directory

    (+ one other header I don’t remember)

    solution: drop the .h off the #include, so: #include

    RCC: Error in ‘resources.qrc’: Cannot find file ‘resources/graphics/rainbow.png’
    make: *** [qrc_resources.cpp] Error 1

    missing graphic, I presume, I’ll just chuck something there temporarily.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>