First steps with QML

QML is a new markup language for building user interfaces. Its main task is to provide the ability to easily and quickly create applications with a beautiful, animated interface.

Not so long ago, a public version was released. This means that the API as a whole has stabilized, and the version can be safely tested and used.

Declarative UI is planned to be included in the Qt 4.7 release, but for now you can find all the necessary files and instructions for installing trolls on ftp.

In this article, I would like to show how you can use C ++ objects (QObject) in qml.

The first step is to download from ftp and build qt-4.6.0-declarative.tar.gz. Alternatively, you can use the already built QtCreator, which contains the necessary libraries.

Let’s create a project

The easiest way is to create a Qt4 application through QtCreator GUI, QWidget is perfect as a base class – qmltest.pro

SOURCES += main.cpp \
widget.cpp \
myobject.cpp
HEADERS += widget.h \
myobject.h
QT += declarative \
script

The header file of our widget – widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
class QmlView;
class MyObject;
class Widget : public QWidget
{
  Q_OBJECT
public:
  explicit Widget(QWidget *parent = 0);
private:
  QmlView *view;
  MyObject *object;
private slots:
  void onSceneResized(QSize size);
};

#endif // WIDGET_H

For starters, it would be nice to remove the system header and make the background transparent:

setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_NoSystemBackground);
view = new QmlView(this);
view->viewport()->setAutoFillBackground(false);

Now we initialize our QML viewer and give it the path to the file that we are going to execute:

view->setFocus();
QString filename = qApp->applicationDirPath() + "/qmlpopups/default/popup.qml";
view->setUrl(QUrl::fromLocalFile(filename));//url - main.qml

Now comes the fun part: making the object’s C ++ properties visible from the qml file. This requires that the object inherits from QObject. Using the Q_PROPERTY macro, properties are made available from qml objects and javascripts.

Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
  • READ indicates which function to use to get the value
  • WRITE indicates which function is used to modify
  • NOTIFY indicates what signal is called when the value changes, used in bindings

Having prepared the object appropriately, we will be able to access these properties from qml.

view->rootContext()->setContextProperty("MyObject",object);
view->rootContext()->setContextProperty("MyText","Hello, QML!");
view->rootContext()->setContextProperty("Avatar",qApp->applicationDirPath() + "/qmlpopups/default/star.png");

Adding new objects is done via QmlContext, the pointer to which is returned by the rootContext () function. You can add both individual properties and whole objects.

Now let’s move on to the qml file itself:

Rectangle {
  id: rect
  width:250
  height: 100
  height: Behavior { NumberAnimation { duration: 1000; easing: "InOutQuad" } }
  color: "transparent"
}

The code draws us a 250×100 rectangle with a transparent fill.

There would be nothing tricky here, if not for a strange property:
height: Behavior {NumberAnimation {duration: 1000; easing: “InOutQuad”}}

The Behavior property tells us how the object behaves when the height value changes. In this case, it should be animation. For any action that sets a new value for the height, the rectangle will not immediately accept this value, but only after performing a certain sequence of actions, which is very convenient when creating an animated gui.

BorderImage {
  source: "background.png"
  height: rect.height
  width: rect.width
  border.left: 20
  border.top: 20
  border.bottom: 20
  border.right: 20
}

This block demonstrates the creation of a background image with a frame. And this is all from one picture, you no longer need to cut it by hand, everything will be done for you, you just need to specify the size of the borders. I think a lot of web designers are jealous now.

To make the picture automatically resize to fit the rectangle, you can use property binding in qml objects, its essence lies in the fact that the value of one parameter is bound to the value of another and automatically changes when the value of the original parameter is changed.

Now let’s write the text

Text {
  id: title
  text: MyText
  font.pointSize: 14
  wrap: true
  color: "white"

  effect: DropShadow {
  color: "white"
  blurRadius: 2
  offset.x: 0
  offset.y: 0
  }

  anchors.top: rect.top
  anchors.topMargin : 5
  anchors.left: avatar.right
  anchors.leftMargin : 5
}

For placing elements in qml, anchors are used, which indicate the position of the object relative to other objects, which turns out to be very convenient. You can apply various effects to text, such as a drop shadow effect. The text itself is taken from the context that we specified earlier. The wrap value indicates line breaks to be done

Text {    
  id: body
  text: MyObject.text
  font.pointSize: 12
  wrap: true
  color: "white"
    
  //ancors
  anchors.top: title.bottom
  anchors.topMargin: 5
  anchors.right: rect.right
  anchors.rightMargin: 5
  anchors.left: avatar.right
  anchors.leftMargin : 5

  onTextChanged: rect.height = calculateMyHeight();
}

This block contains a slot that is activated whenever the text changes, and calls a javascript function that recalculates the height of the entire rectangle that contains our scene. And the text can be changed simply by calling the setText function on our C ++ object.

In the scripts block, you can describe javascript, through which you can interact with any qml objects