Subnavigation

Qt Declarative UI

We've hinted a bit about the Declarative UI part of Kinetic. Well, now it's time to take a look.

First, here is a video of QML in action:

and some more here:

To run the examples for real, either download a binary package including Qt Creator integration, or grab the full source code from the public Gitorious repository.

Declarative UI is a way of making fluid user interfaces by describing them in terms of simple elements (Text, Image, Rect,and other QObjects) that are built up into components. The reason it is "declarative" is that rather than the changes in the UI being expressed as imperative code ("set this, set that, do this, do that, ..."), they are instead expressed as sets of QObject property expressions ("this width is always half that width"), grouped into states ("when enabled, the properties are ..., when disabled, they are ...").  The language that enables this is named QML.  QML is simple yet powerful. Most of a user interface is described by a simple tree structure of property bindings:

import Qt 4.6

Rectangle {
  width: 200
  height: 200
  color: "white"
  Text {
  text: "Hello World"
  anchors.centerIn: parent
  }
}

The power is that those property values can be any JavaScript expression - and because it's a binding rather than just an assignment, the expressions are re-evaluated whenever their dependencies change. This concept has been in Qt forever - if you go back to the old cannon tutorial where a QLCDNumber's display was connected to a QSlider's value, that's a binding: the number displayed changes automatically when the slider value changes.

The fluid part comes from animated transitions between the sets of properties. Combined with Qt's signals and slots, and a little bit of script for the tricky parts, the result is a very powerful technology for making very cool looking UIs that are enjoyable to use.  There is also a set of building blocks useful for creating a fluid UI, including drawing (e.g. Rect, Image), behavior (e.g. MouseRegion, Flickable) and layout (e.g. ListView).  These sorts of fluid user interfaces work well for small simple user interfaces such as those on a phone, or gadget-style desktop applications like media players or VoIP clients. We've put a couple of demos like this in qt/demos/declarative/ directory of the source.

For larger applications, especially on the desktop, fancy effects are currently mainly at the fringes - the bulk of any large application will use traditional widgets (there's a lot of value in desktop consistency!), with just a little "fluidness" at the edges to give the apps a modern feel.

On the web side of things, Declarative UI is completely network transparent - if so configured, Qt will happily load a complete declarative user interface incrementally via HTTP - images and all. And since Declarative UI can use Qt's XQuery support to process other remote data, there are quite a few applications you can write completely in script - no C++ at all.

Qt Declarative integrates perfectly with existing Qt C++ applications.  Qt Declarative components can expose an API with signals, slots, and properties.  For example, the QML below defines a simple button with an API consisting of a label property and the signal clicked():

import Qt 4.6

Rectangle {
id: container
property string label
signal clicked
radius: 5; border.color: "black"
color: mouse.pressed ? "steelblue" : "lightsteelblue"
gradient: Gradient {
GradientStop { position: mouse.pressed ? 1.0 : 0.0; color: "steelblue" }
GradientStop { position: mouse.pressed ? 0.0 : 1.0; color: "lightsteelblue" }
}
MouseRegion { id: mouse; anchors.fill: parent; onClicked: container.clicked() }
Text { anchors.fill: parent; text: container.label; anchors.centerIn: parent }
}

We can create this component in C++ and access its API, just like any other Qt QObject subclass:

QmlComponent component(qmlEngine, "Button.qml");

QObject *button = component.create();

button->setProperty("label", tr("Press Me!"));

connect(button, SIGNAL(clicked()), this, SIGNAL(buttonClicked()));

Qt's data models also work immediately with QML.  Just expose the C++ model to the QML engine:

MyFancyModel *model = new MyFancyModel();

QmlContext *ctxt = canvas->rootContext();

ctxt->setContextProperty("MyModel", model);

Then reference the model's name in QML:

Rectangle {
  width: 800; height: 600; color: "black"

  ListView {
  anchors.fill: parent
  model: MyModel
  delegate: Text { text: display; color: "white" }
  }
}

Declarative UI is a new way to use the core concepts of Qt, so it fits in with your existing code.

We've already started integrating Declarative UI support in Qt Creator. Right now you get QML syntax highlighting and an integrated viewer - check out the Qt Creator blog for details.

And in the KDE playground, there is a demonstration of KDE Plasma integration, so you can run any Declarative UI as a Plasmoid on the desktop!


Blog Topics:

Comments