Vaska el gato
Vaska el gato

Reputation: 198

QML ParentChange transition animation issue

I am not sure if this is a bug in Qt or it's how it should work, but here is a struggle i have:

First, the code that works how i expect it to work:

import QtQuick 2.3
import QtQuick.Window 2.2

  Item {

      width: 200; height: 100
      objectName: "Item"

      Rectangle {
          id: redRect
          objectName: "Red rectangle"
          width: 100; height: 100
          color: "red"
      }

      Rectangle {
          id: blueRect
          objectName: "Blue rectangle"
          x: redRect.width
          width: 50; height: 50
          color: "blue"

          property bool selected: false

          states: State {
              when: blueRect.selected
              name: "reparented"
              ParentChange {
                  target: blueRect
                  parent: redRect
                  width: 10
                  height: 10
              }
          }

          transitions: [
              Transition {
                  from: "*"
                  to: "reparented"

                  ParallelAnimation{
                      ParentAnimation{
                          NumberAnimation{
                              properties: "width, height"
                              duration: 400
                          }
                      }
                      }
                  }
          ]

          onParentChanged: console.log("Parent now is :", parent.objectName)

          MouseArea { anchors.fill: parent; onClicked: blueRect.selected = !blueRect.selected}//blueRect.state = "reparented" }
      }
  }

When clicking on a blue rectangle, it gets reparented to a Red rectangle. The console output is:

qml: Parent now is : Item   <--- When component created
qml: Parent now is : Red rectangle   <--- Reparenting when rectangle was clicked.

I found two cases when reparenting behaves differently. First, if in ParentChange{...} x or y properties are set as a function that returns value:

import QtQuick 2.3
import QtQuick.Window 2.2

  Item {

      width: 200; height: 100
      objectName: "Item"

      Rectangle {
          id: redRect
          objectName: "Red rectangle"
          width: 100; height: 100
          color: "red"
      }

      Rectangle {
          id: blueRect
          objectName: "Blue rectangle"
          x: redRect.width
          width: 50; height: 50
          color: "blue"

          property bool selected: false

          function someFunc() {return 10} // <------ add this line

          states: State {
              when: blueRect.selected
              name: "reparented"
              ParentChange {
                  target: blueRect
                  parent: redRect
                  width: someFunc()    // <--- change here
                  height: someFunc()   // <--- chaghe here
              }
          }

          transitions: [
              Transition {
                  from: "*"
                  to: "reparented"

                  ParallelAnimation{
                      ParentAnimation{
                          NumberAnimation{
                              properties: "width, height"
                              duration: 400
                          }
                      }
                      }
                  }
          ]

          onParentChanged: console.log("Parent now is :", parent.objectName)

          MouseArea { anchors.fill: parent; onClicked: blueRect.selected = !blueRect.selected}//blueRect.state = "reparented" }
      }
  }

And another case is when there is an Anchor change involved. For example:

import QtQuick 2.3
import QtQuick.Window 2.2

  Item {

      width: 200; height: 100
      objectName: "Item"

      Rectangle {
          id: redRect
          objectName: "Red rectangle"
          width: 100; height: 100
          color: "red"
      }

      Rectangle {
          id: blueRect
          objectName: "Blue rectangle"
          x: redRect.width
          width: 50; height: 50
          color: "blue"

          property bool selected: false

          states: State {
              when: blueRect.selected
              name: "reparented"
              ParentChange {
                  target: blueRect
                  parent: redRect
                  width: 10
                  height: 10
              }
              AnchorChanges {
                  target: blueRect
                  anchors.horizontalCenter: parent.horizontalCenter
                  anchors.verticalCenter: parent.verticalCenter
              }
          }

          transitions: [
              Transition {
                  from: "*"
                  to: "reparented"

                  ParallelAnimation{
                      ParentAnimation{
                          NumberAnimation{
                              properties: "width, height"
                              duration: 400
                          }
                      }
                      AnchorAnimation {
                          duration: 400
                      }
                      }
                  }
          ]

          onParentChanged: console.log("Parent now is :", parent.objectName)

          MouseArea { anchors.fill: parent; onClicked: blueRect.selected = !blueRect.selected}//blueRect.state = "reparented" }
      }
  }

In both, second and third cases the output is:

qml: Parent now is : Item   <--- When component is created
qml: Parent now is : Red rectangle   <--- Here is after blue rectangle is clicked
qml: Parent now is : Item   <--- Now this is where it gets glitchy. Blue rectangle gets reparented back to Item
qml: Parent now is : Red rectangle   <--- And now it gets reparented to a Red rectangle back, as i would expect.

Because of this issue, inside of AnchorChanges{} the value returned for parent.vertical/horizontalCenter is the Item when i would expect it to be Red rectangle

So my question is: What could cause this effect, and is this a normal behavior, or it is a bug?

Upvotes: 1

Views: 1079

Answers (1)

Vaska el gato
Vaska el gato

Reputation: 198

I've found a related bug report, so this question can be closed now.

https://bugreports.qt.io/browse/QTBUG-16727

Edit:

Also, this behavior is described in qt documentation as:

State Fast Forwarding

In order for Transition to correctly animate state changes, it is sometimes necessary for the engine to fast forward and rewind a state (that is, internally set and unset the state) before it is finally applied. The process is as follows:

  1. The state is fast forwarded to determine the complete set of end values.
  2. The state is rewound.
  3. The state is fully applied, with transitions.

In some cases this may cause unintended behavior. For example, a state that changes a view's model or a Loader's sourceComponent will set these properties multiple times (to apply, rewind, and then reapply), which can be relatively expensive.

State fast forwarding should be considered an implementation detail, and may change in later versions.

Upvotes: 1

Related Questions