Combining ParentChange with AnchorChanges
-
I'm trying to change parent and anchor at the same time, while animating the anchor change (Qt 5.0.1, Windows):
@import QtQuick 2.0
Item {
id: topItem
width: 200; height: 200Rectangle { id: redRect width: 100; height: 100 x: 20 y: 20 color: "red" } Rectangle { id: blueRect width: 50; height: 50 color: "blue" anchors { top: redRect.top; left: redRect.right } states: State { name: "reparented" AnchorChanges { target: blueRect; anchors.left: redRect.left; } ParentChange { target: blueRect; parent: redRect; } } transitions: Transition { ParentAnimation { via: topItem } AnchorAnimation { duration: 1000 } } MouseArea { anchors.fill: parent; onClicked: blueRect.state = "reparented" } }
}@
The blue box doesn't move to the new position immediately, but jumps to the right first, then moves to the proper position according to the animation; removing ParentAnimation { via: topItem } doesn't fix anything.
I'm doing it because ParentAnimation is limited to x,y animation only, but I want to change the parent as well. If I try to change the parent afterwords, it doesn't work either:
@Item {
id: topItem
width: 200; height: 200Rectangle { id: redRect width: 100; height: 100 x: 20 y: 20 color: "red" } Rectangle { id: blueRect width: 50; height: 50 color: "blue" anchors { top: redRect.top; left: redRect.right } states: State { name: "reparented" AnchorChanges { target: blueRect; anchors.left: redRect.left; } } transitions: Transition { SequentialAnimation{ AnchorAnimation { duration: 1000 } ScriptAction{ script: blueRect.parent = redRect } } } MouseArea { anchors.fill: parent; onClicked: blueRect.state = "reparented" } }
}@
After a correct animation the blue box jumps down. If I remove ScriptAction{ script: blueRect.parent = redRect } it works as expected, but the parent is not changed then.
I would like to ask if it is a bug or am I doing something wrong? And how should I actually do it correctly?
-
Try flipping the state changes around. That worked for me.
@
import QtQuick 2.0Item {
id: topItem
width: 200; height: 200Rectangle { id: redRect width: 100; height: 100 x: 20 y: 20 color: "red" } Rectangle { id: blueRect width: 50; height: 50 color: "blue" anchors { top: redRect.top; left: redRect.right } states: State { name: "reparented" ParentChange { target: blueRect; parent: redRect; } AnchorChanges { target: blueRect; anchors.left: redRect.left; } } transitions: Transition { ParentAnimation { via: topItem } AnchorAnimation { duration: 1000 } } MouseArea { anchors.fill: parent; onClicked: blueRect.state = "reparented" } }
}
@ -
Thanks moeg687. Your code indeed works, but now there is another problem: if I enable clipping on the redRectangle, changing parent via topItem doesn't work, the blueRectangle is still being clipped against the red one:
@import QtQuick 2.0
Item {
id: topItem
width: 200; height: 200Rectangle { id: redRect width: 100; height: 100 clip: true x: 20 y: 20 color: "red" } Rectangle { id: blueRect width: 50; height: 50 color: "blue" anchors { top: redRect.top; left: redRect.right } states: State { name: "reparented" ParentChange { target: blueRect; parent: redRect; } AnchorChanges { target: blueRect; anchors.left: redRect.left; } } transitions: Transition { ParentAnimation { via: topItem } AnchorAnimation { duration: 1000 } } MouseArea { anchors.fill: parent; onClicked: blueRect.state = "reparented" } }
}@
-
This is as close as I can get it. It seems that the blueRect is anchoring to the topItem when animating and then snapping back to it's correct position.
@
Item {
id: topItem
width: 200; height: 200Rectangle { id: redRect width: 100; height: 100 clip: true x: 20; y: 20 color: "red" } Rectangle { id: blueRect width: 50; height: 50 color: "blue" anchors { top: redRect.top; left: redRect.right } states: State { name: "reparented" ParentChange { target: blueRect; parent: redRect } AnchorChanges{ target: blueRect; anchors.left: redRect.left } } transitions: Transition { ParentAnimation { via: topItem AnchorAnimation { duration: 1000 } } } MouseArea { anchors.fill: parent onClicked: blueRect.state = "reparented" } }
}
@I even tried changing the parent after the anchor change using a timer but that seemed to mess up the blueRect's position. I'm not quite sure what's happening here. Could be a bug.
Does your project absolutely require anchors?
@
Item {
id: topItem
width: 200; height: 200Rectangle { id: redRect width: 100; height: 100 clip: true x: 20; y: 20 color: "red" } Rectangle { id: blueRect width: 50; height: 50 color: "blue" x: redRect.x + redRect.width y: redRect.y states: State { name: "reparented" ParentChange { target: blueRect; parent: redRect; x: 0 } } transitions: Transition { ParentAnimation { via: topItem NumberAnimation { property: "x"; duration: 1000 } } } MouseArea { anchors.fill: parent onClicked: blueRect.state = "reparented" } }
}
@ -
Your last code sample works, since it uses the built-in properties of ParentChange - "x" and "y", and your solution is probably as good as it can be at the moment.
What I was concerned about is that using anchors seems much cleaner, than setting "x" and "y", especially if I want to draw something in the middle of something else, where it becomes really kinda ugly x: parent.x + parent.width/2 - width/2. But what can we do... I will probably just avoid using re-parenting =)
ps: I've opened a bug report: "QTBUG-30723":https://bugreports.qt-project.org/browse/QTBUG-30723
-
From the bug report's comments I understood, that the logic behind all this is the following: while items are static they store relative x/y coordinates, so the blueRect has x/y relative to the topItem; when ParentChange happens Qt simply changes the scene graph by changing the parent of blueRect to the redRect. The x/y coordinates now become relative to the redRect, and since anchors are not reevaluated at the ParentChange jump occurs.
It just came to me now, as I realized that only y coordinate snaps, how to solve it: We have to specify all anchors again in the AnchorChanges! Here is the solution/workaround to the problem:
@
Item {
id: topItem
width: 200; height: 200Rectangle { id: redRect clip: true width: 100; height: 100 x: 20 y: 20 color: "red" } Rectangle { id: blueRect width: 50; height: 50 color: "blue" anchors { top: redRect.top; left: redRect.right } states: State { name: "reparented" AnchorChanges { target: blueRect; anchors.left: redRect.left anchors.top: redRect.top } } transitions: Transition { SequentialAnimation{ AnchorAnimation { duration: 1000 } ScriptAction{ script: blueRect.parent = redRect } } } MouseArea { anchors.fill: parent; onClicked: blueRect.state = "reparented" } }
}
@I've opened a suggestion "QTBUG-30772":https://bugreports.qt-project.org/browse/QTBUG-30772 to fix this issue.