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: 200

    Rectangle {
        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: 200

    Rectangle {
        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.0

    Item {
    id: topItem
    width: 200; height: 200

        Rectangle {
                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: 200

        Rectangle {
                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: 200

    Rectangle {
        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: 200

    Rectangle {
        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



  • Yeah anchoring is much cleaner. You can still use anchoring. It is the re-parenting that seems to ruin the object's position. Is there any reason why you need to re-parent the object in the first place?



  • Honestly, while trying to figure out how to work it out, I forgot why I needed re-parenting in the first place =)



  • 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: 200

    Rectangle {
        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.



  • Thanks maxus for posting your find! It makes sense now.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.