Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Combining ParentChange with AnchorChanges
QtWS25 Last Chance

Combining ParentChange with AnchorChanges

Scheduled Pinned Locked Moved QML and Qt Quick
9 Posts 2 Posters 2.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    maxus
    wrote on last edited by
    #1

    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?

    1 Reply Last reply
    0
    • M Offline
      M Offline
      melghawi
      wrote on last edited by
      #2

      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"
                  }
          }
      

      }
      @

      1 Reply Last reply
      0
      • M Offline
        M Offline
        maxus
        wrote on last edited by
        #3

        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"
                   }
            }
        

        }@

        1 Reply Last reply
        0
        • M Offline
          M Offline
          melghawi
          wrote on last edited by
          #4

          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"
              }
          }
          

          }
          @

          1 Reply Last reply
          0
          • M Offline
            M Offline
            maxus
            wrote on last edited by
            #5

            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

            1 Reply Last reply
            0
            • M Offline
              M Offline
              melghawi
              wrote on last edited by
              #6

              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?

              1 Reply Last reply
              0
              • M Offline
                M Offline
                maxus
                wrote on last edited by
                #7

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

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  maxus
                  wrote on last edited by
                  #8

                  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.

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    melghawi
                    wrote on last edited by
                    #9

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

                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved