Monday, January 3, 2011

First QML tutorial

Hello there people,

Here comes finally my first little introduction to QML. Well, I’ve been talking a lot about it… Finally you’ll understand why.

I have installed Qt 4.7.1 and QtCreator (which version, I don’t remember and anyway, it’s not very important for you). I just generated a normal QML project, and here is what I get:
import QtQuick 1.0

Rectangle {
    width: 360
    height: 360
    Text {
        anchors.centerIn: parent
        text: "Hello World"
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }
}
It is really important for you to understand this small code although it is actually self-explaining… I know, you are not stupid, but I’ll do it anyway. :)


As you can read, the root component is a Rectangle. And it is necessary to be a Rectangle to make sure we can see something since the basic shape of all QML applications has to be a Rectangle object. This rectangle has obviously some internal properties such as width, height, color, etc. I will come back to that later.

EDIT 3: It can also be an Item component. But I feel using Rectangle is more convenient, since it has a default background unlike the Item.

In our Rectangle, we include a Text element which also has some properties such as text (the text to display), width, height, etc. Of course, all properties linked to the font size, color and family can be changed. The anchors group of properties refers to how the element will be linked to some other elements. QML works in a parent/children way. You can anchor a child to a parent or two siblings together. So I guess you understood that anchors.centerIn: parent allows the text to be centered in the parent element and this will work even if the size changes.

The second element is a MouseArea. This element allows you to handle click events (simple, double, hold, release, etc.) and by catching the event, you can do something. In this case, we just close the application. The MouseArea is anchored to the parent; it is filling the complete space. So far, as I said it’s self-explaining.

From my point of view, this basic QML code is missing something. Indeed, although it’s clear and short, I actually feel that the following code would be better like this:
import QtQuick 1.0

Rectangle {
    id: hello_root
    width: 360
    height: 360
    Text {
        id: hello_text
        anchors.centerIn: parent
        text: "Hello World"
    }
    MouseArea {
        id: hello_msa
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }
}
The difference is light but it’s very important! As I said before, everything works as parent/children. A child can refer to a parent just by using the parent keyword. However, to anchor two children together, the only way to do it is by using the id of the element. Therefore as a first good practice, I’m begging you to always add the id property. And please, keep it clear! This is VERY important. Having a file with all text elements being called like text1, text2, text3, etc. is simply disgusting from my point of view.

So far, so good, if we run that, we obtain this:
Not very exciting I know. But as I said, you can play with some properties so, just for the purpose of this short introduction and because it’s the beginning of the year, here is a version which is a bit funnier:
Here is the code:
import QtQuick 1.0

Rectangle {
    id: happy_root
    width: 360
    height: 360
    color: "darkgrey"

    Rectangle{
        id: happy_circle_red
        x: 31
        y: 97
        width: 41
        height: 41
        radius: width/2
        color: "red"
    }

    Rectangle{
        id: happy_circle_blue
        x: 68
        y: 248
        width: 20
        height: 20
        radius: width/2
        color: "blue"
    }

    Rectangle{
        id: happy_circle_yellow
        x: 142
        y: 121
        width: 28
        height: 28
        radius: width/2
        color: "yellow"
    }

    Rectangle{
        id: happy_circle_pink
        x: 221
        y: 233
        width: 54
        height: 54
        radius: width/2
        color: "pink"
    }

    Rectangle{
        id: happy_circle_green
        x: 271
        y: 72
        width: 63
        height: 63
        radius: width/2
        color: "lightgreen"
    }

    Text {
        id: happy_text
        anchors.centerIn: parent
        color: "blue"
        font.pointSize: 16
        font.bold: true
        text: "Happy New Year"
    }

    MouseArea {
        id: happy_msa
        anchors.centerIn: parent
        onClicked: {
            Qt.quit();
        }
    }
}
You might think: “Woaw, that’s… useless” but you are wrong. And you’ll understand why in the next tutorial where I will teach you how to make your own QML elements so that the code doesn’t look big for nothing as it is right now. So stay tuned. ;)

EDIT: Well, it seems something is not very clear, my bad. I didn't explain it.

The radius property which is added to the Rectangle allows to have rounded corners. If you look closely to the code, you can see:
radius: width/2
This simply means that I use the width of the Rectangle and dividing it by 2 allows me to create a circle. This is a small trick, and I apologize for missing to explain it.

In QML, you can call almost all properties from the current object or any other object as long as you know the id that's why I'm begging you to use understandable and practical id names. :)

EDIT 2: Thanks to one of the reader, one little "error" has been found.

Indeed, in the last example, for the MouseArea, you can see anchors.centerIn. This property makes no sense in this case. It makes more sense to change it to anchors.fill. Line 71 should now be:
anchors.fill: parent
This error might come from a bad copy/paste. :(

7 comments:

  1. Nice!
    Thanks for this first tutorial of QML!

    I've been programming in Qt/C++ for a while but I think I will switch to QML!
    It seems very easy and "quick" to deploy new GUI applications with QML!

    ReplyDelete
  2. Thanks for your explanation about the radius ;)

    I have another question about the difference between QtQuick and Qt.
    I can start the same program with "import Qt 4.7" instead of "import QtQuick 1.0" at the beginning of the file.
    The result is the same... and both are quick (at least impossible to tell the difference with such a small program).

    Is there any difference or both are the same?
    Maybe QtQuick imports less libraries than Qt only?

    ReplyDelete
  3. So far, I was also surprised to see this "import QtQuick" because I always just had "import Qt 4.x". At the beginning, it was 4.6 now it's 4.7.
    I'm not sure what exactly is the difference between these 2 imports. As far as I can tell, it's working the same way for the example. Maybe when I'll go deeper in the tutorial, I'll notice what exactly is the difference.
    To make sure that everything is correct, import Qt 4.7 rather QtQuicck. I'll keep importing QtQuick in this tutorial as long as it will work ;)
    It can be also possible that QtQuick is an alias for the Qt version in the PATH. ;)

    ReplyDelete
  4. Your tutorial rocks!!. I am a newbie or rahter hobbyist who loves python. and also a bit of ruby. I have seen some other QML basic tutorial but your style of explanation and presentation is the best i have seen. Its really great!!. It would be great if you could make a series of tutorials like this for QML starting from the basics.

    Thanks and keep up the good work!.

    Everest.

    ReplyDelete
  5. Thanks a lot Everest, I'll try to continue with these tutorials asap. I'm a bit busy right now with something else, but I'll do the next one soon (hopefully).

    ReplyDelete
  6. In the final example I needed to put in anchors.fill: parent on line 71 to get the mouse click to work (I was using import Qt 4.7; don't know if that makes a difference).

    ReplyDelete
  7. Thanks for noticing it. I don't even remember changing this property to "centerIn". Of course, "fill" makes more sense. Thanks offaxis. :)

    ReplyDelete