Wednesday, October 27, 2010

First learning project with QML, the very basics - how to make a button

There has been a lots of discussion about the QML recently, so I decided to look at it myself as well. I think that QML is a very good new technology in the Qt and it makes it very much easier to implement out of the box UIs which are not bound to traditional UI logic, e.g. to what for example traditional desktop toolkits (like gtk+) tends to limit.

After one evening of doing things with varying success (in some places syntax is a bit weird and it required some patience to get over it) for one evening and I got a simple button and a dialpad with buttons implemented. Well it is not very usable dialpad, it even does not have 0 or any other buttons that might be necessary on it. Actually I was thinking of doing a calculator and that's why I collected the buttons like this. I did not try it on N900 yet, but started trying it out on desktop because it is the fastest way to learn this new thing. After getting into it it started to feel pretty nice and many of the difficulties I immediately faced in the beginning were RTFM errors. Good idea is to read some documentation about it before swearing too many curse words - after all it is not bad at all. I got some help from Kate Alhola who is a guru with the QML already and it saved my time a little bit.

Here is what I did: I downloaded latest Qt SDK 4.7.0 to my Mac. I also installed it on my Linux laptop, but this example I created in the evening on Mac. I created empty QML project with Qt Creator. I added the following files to the project.

qmlwiz.qml (this is going to be my main, renders here a numeric keypad)
SimpleButton.qml (this contains the button code)

Unfortunately Blogger strips down all indents and the code looks a bit ugly, but I hope you can still read it somewhat. At least this is quite short reducing the chance of confusion.

SimpleButton.qml:



import Qt 4.7

Rectangle {
id: simpleButton
width: 60; height: 60;
radius: 10
border.color: "gray"
border.width: 2

gradient: Gradient {
GradientStop { position: 0.0; color: "gray" }
GradientStop { position: 0.33; color: "lightgray" }
GradientStop { position: 1.0; color: "darkgray" }
}

states: [
State {
name: "up"
PropertyChanges { target: down_anim; running: false }
PropertyChanges { target: up_anim; running: true }
},

State {
name: "down"
PropertyChanges { target: down_anim; running: true }
}

]
// transition is unfinished, possibly not needed at all, because states take care of it
transitions: [
Transition {
from: "up"; to: "down"
}
]


MouseArea {
anchors.fill: parent
onPressed: parent.state = "down"
onReleased: parent.state = "up"
}

SequentialAnimation {
id: down_anim
NumberAnimation {
target: simpleButton; properties: "scale"
from: 1.0; to: 0.8; duration: 100
easing.type: "OutExpo"

}
NumberAnimation {
target: simpleButton; properties: "opacity"
from: 1.0; to: 0.5; duration: 100
easing.type: "OutExpo"
}

running:false
}
SequentialAnimation {
id: up_anim

NumberAnimation {
target: simpleButton; properties: "opacity"
from: 0.5; to: 1.0; duration: 10
easing.type: "OutExpo"
}
NumberAnimation {
target: simpleButton; properties: "scale"
from: 0.8; to: 1.0; duration: 10
}

running:false
}


Text {
anchors.centerIn: parent
id: button_text
text: "0"
}
property alias label: button_text.text

}




qmlwiz.qml:




import Qt 4.7

Rectangle {
width: 800
height: 480

transform: Rotation { origin.x: 30; origin.y: 30; axis { x: 0; y: 1; z: 0 } angle: -10 }
Rectangle {
SimpleButton { x:100; y:100; label: "7" }
SimpleButton { x:100; y:100+64; label: "4" }
SimpleButton { x:100; y:100+64+64; label: "1" }
SimpleButton { x:100+64; y:100; label: "8" }
SimpleButton { x:100+64; y:100+64; label: "5" }
SimpleButton { x:100+64; y:100+64+64; label: "2" }
SimpleButton { x:100+64+64; y:100; label: "9" }
SimpleButton { x:100+64+64; y:100+64; label: "6" }
SimpleButton { x:100+64+64; y:100+64+64; label: "3" }

Text {
text: "Karoliina's Magic Keypad"
}
}
}


To run the application, there is a button with green triangle on near to the bottom of the left hand side toolbar on the Qt Creator. When the main program file is selected on the file list and this button is pressed, the program is run from Main.

I looked the documentation further and discovered that there is also a repeater functionality which can be used to build e.g. the dialpad or calcpad shown above without repeating the SimpleButton instantiations manually for each number.

There is plenty of room to make this nicer, actually I like a lot a such button that is composited from two layers: basic layer illustrates the button itself. Then a translucent highlight layer is composited on top of the button when press down occurs. When mouse button release occurs, the composited top layer is faded away with alpha channel ramp. I may try that next, but I did not have time to do the graphics for the highlight yet (as it looks the best when it is made with e.g. Inkscape and not attempted computationally). I may try that later. Now I wanted to finish something before going to sleep.

Bottom line is that QML is very nice and super easy. With short time it is possible to learn to do some quite nice things already. I rotated the scene a bit because I like how the menus on Colin McRae: Dirt are rotated. Actually with QML it is very easy to make similar dynamic animated rotation so that the scene slightly turns by itself on time back and forth. To do that, I was thinking using the NumberAnimation. I may try that after doing the composited button which I think is even cooler. Then I need to also hook these to C++ application to do the calculation logic on the C++ side. Kate has a nice AR-Drone control app doing this exactly already, so I need to look her code to see how to do it. Quick look reveals that it is very easy. I need to try maybe tomorrow if I have time.

1 comment:

Jyrki Heikkinen said...

"Unfortunately Blogger strips down all indents and the code looks a bit ugly..."

To keep indentation, add the HTML pre tags around the code (in Blogger's HTML editor).