вторник, 31 января 2012 г.

Qt Quick - простая анимация

Qt Quick - простая анимация
(релиз Qt SDK на момент написания данной статьи - 1.1.4)

В этой статье я вас покажу простой пример того, как на языке QML можно сделать анимированное передвижение объектов.



Для начала небольшая вводная. В этой статье мы будем оперировать таким понятие как State (состояние). Любой объект в QML (будь то Rectangle, TextInput, Text и тыды) может иметь несколько состояний.
Например мы можем определить для прямоугольника 2 состояния:
1. Начальное, когда он размером 500 на 500 и имеет серый цвет
2. Второе состояние, когда он будет красного цвета размером 700 на 100
3. Ещё одно состояние, когда он будет скажем зеленый, размером 300 на 300

Как это делается?

Для начального состояния мы создаём простой прямоугольник, как мы это делали в статье http://easy-qt.blogspot.com/2012/01/hello-world-v3-qt-quick-edition.html

Так как прямоугольник верхнего уровня задаёт размеры окна, сначала мы создадим окно, а внутрь него поместим наш прямоугольник из примера. Изменим его свойства таким образом, чтобы оно подходило под наш пример:

import QtQuick 1.0
Rectangle
{
    width: 800
    height: 600
    Rectangle {
        id: rec
        width: 500
        height: 500
        color: "gray"
    }
}
У нас добавились 2 ранее не описанных поля: id и color. color - цвет прямоугольника, а ID - идентификатор, через который мы в дальнейшем сможем работать с нашим прямоугольником.

Как видите, наш прямоугольник уже находится в начальном состоянии и нам не потребуется описывать его в дальнейшем.

Теперь нам необходимо задать второе и третье его состояние. В состояниях мы указываем те свойства, которые должны поменяться. Записывается это следующим образом:

import QtQuick 1.0
Rectangle
{
    width: 800
    height: 600
    Rectangle {
        id: rec
        width: 500
        height: 500
        color: "gray"
        //---------------------------------------------------------------------
        // Новый текст
        states: [
            State {
                name: "StateDva"
                PropertyChanges {
                    target: rec
                    width: 700
                    height: 100
                    color: "red"
                }
            }
        ]
        //---------------------------------------------------------------------
    }
}
Здесь мы определяем свойство states нашего прямоугольника. Как видите, мы создаём новый объект типа State, задаём его имя и указываем что меняется в этом состоянии (Property Changes).Свойства мы задали в соответствии с желаемым вторым состоянием.
Я думаю вам бы теперь хотелось посмотреть на это самое состояние. Будем переходить в это состояние по клику мыши на этом самом прямоугольнике. Для этого нам необходимо добавить в прямоугольник область обработки действий мыши, и когда будем кликать в этой области, переводить объект во второе состояние.
import QtQuick 1.0

Rectangle
{
    width: 800
    height: 600
    Rectangle {
        id: rec
        width: 500
        height: 500
        color: "gray"
        MouseArea
        {
            anchors.fill: parent
            onClicked: rec.state = "StateDva"
        }
        //---------------------------------------------------------------------
        // Новый текст
        states: [
            State {
                name: "StateDva"
                PropertyChanges {
                    target: rec
                    width: 700
                    height: 100
                    color: "red"
                }
            }
        ]
        //---------------------------------------------------------------------
    }
}
Теперь вы можете запустить приложение, и кликнуть по прямоугольнику. Как видите, переход происходит. Но на мой взгляд он смотрится как-то убогенько. Сделаем это дело плавным и красивым. Для этого мы добавим переход.
import QtQuick 1.0

Rectangle
{
    width: 800
    height: 600
    Rectangle {
        id: rec
        width: 500
        height: 500
        color: "gray"
        MouseArea
        {
            anchors.fill: parent
            onClicked: rec.state = "StateDva"
        }
        states: [
            State {
                name: "StateDva"
                PropertyChanges {
                    target: rec
                    width: 700
                    height: 100
                    color: "red"
                }
            }
        ]
        //---------------------------------------------------------------------
        // Новый текст
        transitions: [
            Transition {
                from: ""
                to: "StateDva"
                NumberAnimation {
                    target: rec
                    properties: "height, width"
                    duration: 800
                }

            }
        ]
        //---------------------------------------------------------------------
    }
}

Аналогично свойству states: мы создаём новый объект для свойства transitions. Внутри мы определяем, для какого перехода будет применяться данная анимация (from, to). Пустое название состояния - изначальное состояние объекта. В качестве имени состояния вы также можете указать "*". Звезда означает - любое состояние.
т. е. запись 
from: "*"
to: "*"
будет обозначать "При любом переходе".
Внутри мы указываем числовую анимацию (NumberAnimation) для объекта, свойств, и собственно время этой самой анимации. Пробуем.
Прямоугольник конечно изменяется красиво, но цвет меняется слишком резко. Значит надо добавить анимацию для цвета:
import QtQuick 1.0
Rectangle
{
    width: 800
    height: 600
    Rectangle {
        id: rec
        width: 500
        height: 500
        color: "gray"
        MouseArea
        {
            anchors.fill: parent
            onClicked: rec.state = "StateDva"
        }
        states: [
            State {
                name: "StateDva"
                PropertyChanges {
                    target: rec
                    width: 700
                    height: 100
                    color: "red"
                }
            }
        ]
        transitions: [
            Transition {
                from: ""
                to: "StateDva"
                NumberAnimation {
                    target: rec
                    properties: "height, width"
                    duration: 800
                }
                //---------------------------------------------------------------
                // Новый текст
                ColorAnimation {
                    target: rec
                    duration: 800
                }
            }
        ]
        //---------------------------------------------------------------------
    }
}

Как вы можете видеть, внутри одного перехода находятся несколько типов анимаций. Их можно выполнять как параллельно, так и по очереди, но об этом в следующий раз.

Добавим третье состояние:
import QtQuick 1.0
Rectangle
{
    width: 800
    height: 600
    Rectangle {
        id: rec
        width: 500
        height: 500
        color: "gray"
        MouseArea
        {
            anchors.fill: parent
            onClicked: rec.state = "StateDva"
        }
        states: [
            State {
                name: "StateDva"
                PropertyChanges {
                    target: rec
                    width: 700
                    height: 100
                    color: "red"
                }
            }
                //---------------------------------------------------------
                // Новый текст
                 ,
            State {
                name: "StateTri"
                PropertyChanges {
                    target: rec
                    width: 300
                    height: 300
                    color: "green"
                }
            }
            //-----------------------------------------------------------
        ]
        transitions: [
            Transition {
                from: ""
                to: "StateDva"
                NumberAnimation {
                    target: rec
                    properties: "height, width"
                    duration: 800
                }
                ColorAnimation {
                    target: rec
                    duration: 800
                }
            }
        ]
    }
}
Ну а теперь нам надо посмотреть на это состояние, изменим обработки MouseArea по клику мыши, добавив условный оператор. 
    onClicked: if (rec.state == "") rec.state = "StateDva"
               else rec.state = "StateTri"

Теперь у вас есть прямоугольник с тремя состояниями. Попробуйте поэкспериментировать с Переходами (испробуйте *, добавьте ещё один передох и тыды).








5 комментариев:

  1. Этот комментарий был удален автором.

    ОтветитьУдалить
  2. Запутался в скобках и еще надо же прописать, что после одного State надо поставить "," и только потом писать другой State, также и с Transition (добавил Transition еще и к переходу на зеленый квадрат) долго искал эту запятую!))

    А как произвольную фигуру рисовать?

    ОтветитьУдалить
  3. Базовых путей для построения произвольной фигуры к сожалению нет.
    Можно либо добавить картинку, либо делать рисование через QObject, но оба пути не ахти :(

    ОтветитьУдалить
  4. Хотелось бы увидеть побольше простых уроков с подробными объяснениями, так сказать, для новичков и среднего класса.
    Например в одном из уроков видел запись следующего характера:
    (К примеру, уже не помню где видел)
    .h
    QLabel *lbl; //знающие поймут, а для остальных я потом расскажу, и так и не рассказано. Понятно, что это указатель на объект класса, понятно что он дан в .h для того чтобы объект класса был виден в контексте программы. Но почему именно указатель на объект, почему не объект? Ну и т.п.

    ОтветитьУдалить
  5. Очень интересный урок! Спасибо!
    При попытке прописать переходы не для всех статусов сразу, а по отдельности, программа выдавала ошибку.
    Понял, что дело в неверном "синтаксисе". Сразу не уяснил, что нужно ставить запятые между операторами.
    Далее, как нужно:
    Transitions: [
    Transition{...}
    ,
    Transition{...}
    ,
    Transition{...}
    ]
    p.s. может кому-то покажется дикой глупостью, но промучился я в поисках моей ошибки около часа. Может кому-то поможет.

    ОтветитьУдалить