2012-09-06

Property Animation in QML

It has been a long time since I put up a post, I'll try to post more often.  I'm posting up some code I wrote to make a button pulse after clicked and then quit pulsing when clicked again.  Simple, but it contains some important examples of syntax and implementation.  I hope somebody finds it useful.  
Start up QtCreator and select File/New File or Project.../Applications/QtQuick Application (Built-in Elements).  Enter a name and then select only Desktop.  Will it work on the other platforms?  Probably, but I haven't tested it on any but Desktop, so that is why I'm suggesting you do the same.  Just copy and paste this code over the main.qml and it should run.


import QtQuick 1.0

Rectangle {
    width: 400
    height: 400

    Rectangle {
        id: applyButton

        width: 100
        height: 30
        border.color: "#4f78a2"
        border.width: 2
        radius: 5
        smooth: true
        anchors.centerIn: parent
        color: "#BFEFFF"
        opacity: 1.0

        Text {
            id:textItem
            anchors.centerIn: parent
            font.pointSize: 12
            font.family: "Helvetica"
            color: "#337777"
            styleColor: "#ffffff"
            style: Text.Raised

            text: "Apply"
        }

        PropertyAnimation {
            id: changeToColor1;
            target: applyButton;
            properties: "color";
            to: "#ffff00";
            duration: 1000
        }

        PropertyAnimation {
            id: changeToColor2;
            target: applyButton;
            properties: "color";
            to: "#BFEFFF";
            duration: 1000
        }

        NumberAnimation {
            id: toFullOpacity
            target: applyButton
            properties: "opacity"
            to: 1
            duration: 250
            exclude: border
        }

        SequentialAnimation {
            id: sequentialOpacity
            running: false

            NumberAnimation {
                id: animateOpacity
                target: applyButton
                properties: "opacity"
                from: .2
                to: 1
                duration: 700
                easing {type: Easing.InOutQuad; }
                exclude: border
            }
            NumberAnimation {
                id: animateOpacity2
                target: applyButton
                properties: "opacity"
                to: .2
                from: 1
                duration: 700
                easing {type: Easing.InOutQuad;}
                exclude: border
            }
            loops: Animation.Infinite
        }

        MouseArea {
            id: applyButtonMA
            anchors.fill: parent
            //hoverEnabled: true
            onClicked: {
                if (sequentialOpacity.running == true)
                {
                    sequentialOpacity.stop()
                    toFullOpacity.start()
                    changeToColor2.start()
                }
                else
                {
                    changeToColor1.start()
                    sequentialOpacity.start()
                }
            }
        }
    }
}

                                         



When you click the button the first time, it will turn to yellow and start to pulse ( the opacity will cycle from 1.0 to 0.1 and back again over and over ).

When you click it again, it will return to it's initial state as a light blue button.  

I really love how you just put an id on an item and then you can refer to it later by that id.  Like:
   sequentialOpacity.stop()

It's quick object notation.  Since sequentialOpacity (my name) is an instance of SequentialAnimation I can use dot notation to access any of SequentialAnimation's functions.

QML is not exactly the "plain english" language that it appears to be.  Even the syntax can get a bit wonky at times and leave me scratching my head as to WHY is this element in this syntax, while all the rest are written a different way.  For example, take this bit of code from above:


            NumberAnimation {
                id: animateOpacity2
                target: applyButton
                properties: "opacity"
                to: .2
                from: 1
                duration: 700
                easing {type: Easing.InOutQuad;}
                exclude: border
            }
Apparently "easing" is an object? All the other properties use the colon notation, but then easing pops in using the syntax of an entire object. It could have been written like this:

 
            NumberAnimation {
                id: animateOpacity2
                target: applyButton
                properties: "opacity"
                to: .2
                from: 1
                duration: 700
                easing {
                   type: Easing.InOutQuad;
                }
                exclude: border
            }
Thinking of easing as a property had me coding with the wrong syntax for a while, and the error messages are not always specific enough to lead to proper correction. Eventually I ran into just one example on the inter-webs with the proper syntax and I fixed it, but it took some digging and sleuthing, and this sort of thing is a serious waste of valuable time.

"exclude: border" does not work either, by the way. I have no idea why. And QtCreator rejected entirely "exclude: border.color". Gave up on that one.

 Anyway, play with this and see if it helps you understand QML a little better. Let me know if you have any suggestions or questions. I've been working with QML for a couple of months now, and I've learned how to do a few things. If you are learning this powerful language ( and possibly Qt alongside of it as well ) then you have probably found that documentation of some of the simplest things is hard to find. I'm one who believes that documentation needs to include comprehensive examples, definitions and references to relative terms if it dares call itself documentation. As "extensive" as the Qt and QML documentation is, it lacks terribly in explanations, clarifications of concepts, and easy to read specific examples. IF you already know what you are doing, then it is an adequate reference, but even then I often run into dead ends.

Here are some more of my thoughts on that whole situation...

Thanks for reading.

 CHEERS! ultramanjones

1 comment:

  1. easing is a group property, just like font. Group properties can be set two ways. The shorthand way where you start with a curly brace and then a list of the property value pairs.

    easing { type : Easing.OutBack
    overshoot: 1.5}

    Or you can just use the dot notation like:

    easing.type : Easing.OutBack
    easing.overshoot: 1.5

    ReplyDelete

Let me know what you think!