Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    [Solved] QML and Drag and Drop

    QML and Qt Quick
    8
    42
    33826
    Loading More Posts
    • 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.
    • K
      kyleplattner last edited by

      So i am trying to find a way to rearrange dashboard widgets for my application. I would to give the user the ability to do this by just pressing and holding on a widget and then dragging it to a new location. Here is an implementation that allows the user to tap the widget he or she wants to change and then move it by tapping a new location. It works but I would love to add drag and drop to this. Please let me know if you have any ideas:

      @import Qt 4.7

      Rectangle {
      width: 640
      height: 480
      color: "#111111"

      Component {
      
      
          id: widgetdelegate
          Item {
              width: grid.cellWidth; height: grid.cellHeight
              Image {
                  source: portrait;
                  anchors.horizontalCenter: parent.horizontalCenter
                  width: grid.cellWidth; height: grid.cellHeight
                  fillMode: Image.PreserveAspectFit
              }
      
      
              MouseArea {
                  id: mouse_area1
                  anchors.fill: parent
                  onClicked: {
                      if (grid.firstIndexDrag== 0) {
                          grid.firstIndexDrag=index
                      }else {
                          widgetmodel.move(grid.firstIndexDrag,index,1)
                          grid.firstIndexDrag= 0
                      }
      
                  }
              }
          }
      }
      
      
      ListModel {
          id: widgetmodel
          ListElement {
              portrait: "Images/widget1.png"
          }
          ListElement {
              portrait: "Images/widget2.png"
          }
          ListElement {
              portrait: "Images/widget3.png"
          }
          ListElement {
               portrait: "Images/widget4.png"
          }
          ListElement {
               portrait: "Images/widget5.png"
          }
          ListElement {
               portrait: "Images/widget6.png"
          }
          ListElement {
               portrait: "Images/widget7.png"
          }
          ListElement {
               portrait: "Images/widget8.png"
          }
          ListElement {
               portrait: "Images/widget9.png"
          }
      
      
      
      }
      
      GridView {
      
          property int firstIndexDrag: 0
      
          id: grid
          x: 0
          y: 0
          anchors.rightMargin: 200
          anchors.bottomMargin: 100
          anchors.leftMargin: 200
          anchors.topMargin: 100
          width: 640
          height: 480
          anchors.fill: parent
          cellWidth: 80; cellHeight: 80
          flow: GridView.LeftToRight
      
      
          model: widgetmodel
          delegate: widgetdelegate
          //highlight: Rectangle { color: "white"; radius: 5 ; z: 1 }
          focus: true
      
      
      }
      

      }
      @

      1 Reply Last reply Reply Quote 0
      • A
        anselmolsm last edited by

        kyleplattner, is it related with "this other thread":http://developer.qt.nokia.com/forums/viewthread/2388?

        Anselmo L. S. Melo (anselmolsm)

        1 Reply Last reply Reply Quote 0
        • K
          kyleplattner last edited by

          Same in concept, different in approach to implementation.

          1 Reply Last reply Reply Quote 0
          • X
            xsacha last edited by

            Hey Kyle. Here is drag and drop for you:

            For the sake of brevity, I have separated your widgetmodel in to another QML file which I won't repeat in future.

            WidgetModel.qml
            @
            import QtQuick 1.0

            ListModel {
            ListElement {
            portrait: "Images/widget1.png"
            }
            ListElement {
            portrait: "Images/widget2.png"
            }
            ListElement {
            portrait: "Images/widget3.png"
            }
            ListElement {
            portrait: "Images/widget4.png"
            }
            ListElement {
            portrait: "Images/widget5.png"
            }
            ListElement {
            portrait: "Images/widget6.png"
            }
            ListElement {
            portrait: "Images/widget7.png"
            }
            ListElement {
            portrait: "Images/widget8.png"
            }
            ListElement {
            portrait: "Images/widget9.png"
            }
            }@

            Main.qml
            @
            import QtQuick 1.0

            Rectangle {
            width: 640
            height: 480
            color: "#111111"
            Component {
            id: widgetdelegate
            Item {
            width: grid.cellWidth; height: grid.cellHeight
            Image {
            source: portrait;
            anchors.horizontalCenter: parent.horizontalCenter
            width: grid.cellWidth; height: grid.cellHeight
            fillMode: Image.PreserveAspectFit
            }
            Rectangle {
            width: parent.width; height: parent.height; radius: 5
            border.color: "white"; color: "transparent"; border.width: 6;
            visible: index == grid.firstIndexDrag
            }
            }
            }

            GridView {
                property int firstIndexDrag: -1
            
                id: grid
                x: 0; y: 0
                interactive: false
            
                anchors.rightMargin: 200
                anchors.bottomMargin: 100
                anchors.leftMargin: 200
                anchors.topMargin: 100
                width: 640
                height: 480
                anchors.fill: parent
                cellWidth: 80; cellHeight: 80
            
                model: WidgetModel { id: widgetmodel }
                delegate: widgetdelegate
                MouseArea {
                    anchors.fill: parent
                    onReleased: {
                        if (grid.firstIndexDrag != -1)
                            widgetmodel.move(grid.firstIndexDrag,grid.indexAt(mouseX, mouseY),1)
                        grid.firstIndexDrag = -1
                    }
                    onPressed: grid.firstIndexDrag=grid.indexAt(mouseX, mouseY)
                }
            }
            

            }@

            You probably want to animate the drag and drop too. But didn't we cover this in the other topic? Please tell me if you desire code for this too.

            • Sacha
            1 Reply Last reply Reply Quote 0
            • K
              kyleplattner last edited by

              I am interested in the code for animating it, thanks. I will try this tonight.

              I really appreciate your help.

              Kyle

              1 Reply Last reply Reply Quote 0
              • X
                xsacha last edited by

                Ok, I used re-parenting to animate the drag:

                @
                import QtQuick 1.0

                Rectangle {
                width: 640
                height: 480
                color: "#222222"
                Component {
                id: widgetdelegate
                Item {
                width: grid.cellWidth; height: grid.cellHeight
                Image {
                id: im
                source: portrait;
                anchors.centerIn: parent
                width: grid.cellWidth - 10; height: grid.cellHeight - 10
                smooth: true
                fillMode: Image.PreserveAspectFit
                Rectangle {
                id: imRect
                anchors.fill: parent; radius: 5
                anchors.centerIn: parent
                border.color: "#326487"; color: "transparent"; border.width: 6;
                opacity: 0
                }
                }
                Rectangle {
                id: iWasHere
                width: 20; height: 20; radius: 20
                smooth: true
                anchors.centerIn: parent
                color: "white";
                opacity: 0
                }
                states: [
                State {
                name: "inDrag"
                when: index == grid.firstIndexDrag
                PropertyChanges { target: iWasHere; opacity: 1 }
                PropertyChanges { target: imRect; opacity: 1 }
                PropertyChanges { target: im; parent: container }
                PropertyChanges { target: im; width: (grid.cellWidth - 10) / 2 }
                PropertyChanges { target: im; height: (grid.cellHeight - 10) / 2 }
                PropertyChanges { target: im; anchors.centerIn: undefined }
                PropertyChanges { target: im; x: coords.mouseX - im.width/2 }
                PropertyChanges { target: im; y: coords.mouseY - im.height/2 }
                }
                ]
                transitions: [
                Transition { NumberAnimation { properties: "width, height, opacity"; duration: 300; easing.type: Easing.InOutQuad } }
                ]
                }
                }

                GridView {
                    property int firstIndexDrag: -1
                
                    id: grid
                    x: 0; y: 0
                    interactive: false
                
                    anchors.rightMargin: 200
                    anchors.bottomMargin: 100
                    anchors.leftMargin: 200
                    anchors.topMargin: 100
                    anchors.fill: parent
                    cellWidth: 80; cellHeight: 80;
                
                    model: WidgetModel { id: widgetmodel }
                    delegate: widgetdelegate
                    Item {
                        id: container
                        anchors.fill: parent
                    }
                    MouseArea {
                        id: coords
                        anchors.fill: parent
                
                        onReleased: {
                            if (grid.firstIndexDrag != -1)
                                widgetmodel.move(grid.firstIndexDrag,grid.indexAt(mouseX, mouseY),1)
                            grid.firstIndexDrag = -1
                        }
                        onPressed: {
                            grid.firstIndexDrag=grid.indexAt(mouseX, mouseY)
                        }
                    }
                }
                

                }@

                Enjoy!

                • Sacha
                1 Reply Last reply Reply Quote 0
                • K
                  kyleplattner last edited by

                  Amazing, very well done. Thanks so much! I owe you a lot.

                  1 Reply Last reply Reply Quote 0
                  • X
                    xsacha last edited by

                    Oh by the way, I read your previous thread and remembered you wanted to have that 'squiggle' thing when the user does an 'onPressAndHold' -- like iOS does. So, I did this too. I hope you learn from the code:

                    Main.qml
                    @
                    import QtQuick 1.0

                    Rectangle {
                    width: 640
                    height: 480
                    color: "#222222"
                    Component {
                    id: widgetdelegate
                    Item {
                    width: grid.cellWidth; height: grid.cellHeight
                    Image {
                    id: im
                    state: "inactive"
                    source: portrait;
                    anchors.centerIn: parent
                    width: grid.cellWidth - 10; height: grid.cellHeight - 10
                    smooth: true
                    fillMode: Image.PreserveAspectFit
                    SequentialAnimation on rotation {
                    NumberAnimation { to: 20; duration: 200 }
                    NumberAnimation { to: -20; duration: 400 }
                    NumberAnimation { to: 0; duration: 200 }
                    running: im.state == "squiggle"
                    loops: Animation.Infinite
                    }
                    Rectangle {
                    id: imRect
                    anchors.fill: parent; radius: 5
                    anchors.centerIn: parent
                    border.color: "#326487"; color: "transparent"; border.width: 6;
                    opacity: 0
                    }
                    states: [
                    State {
                    name: "squiggle";
                    when: (grid.firstIndexDrag != -1) && (grid.firstIndexDrag != index)
                    },
                    State {
                    name: "inactive";
                    when: (grid.firstIndexDrag == -1) || (grid.firstIndexDrag == index)
                    PropertyChanges { target: im; rotation: 0}
                    }
                    ]
                    }
                    Rectangle {
                    id: iWasHere
                    width: 20; height: 20; radius: 20
                    smooth: true
                    anchors.centerIn: parent
                    color: "white";
                    opacity: 0
                    }
                    states: [
                    State {
                    name: "inDrag"
                    when: index == grid.firstIndexDrag
                    PropertyChanges { target: iWasHere; opacity: 1 }
                    PropertyChanges { target: imRect; opacity: 1 }
                    PropertyChanges { target: im; parent: container }
                    PropertyChanges { target: im; width: (grid.cellWidth - 10) / 2 }
                    PropertyChanges { target: im; height: (grid.cellHeight - 10) / 2 }
                    PropertyChanges { target: im; anchors.centerIn: undefined }
                    PropertyChanges { target: im; x: coords.mouseX - im.width/2 }
                    PropertyChanges { target: im; y: coords.mouseY - im.height/2 }
                    }
                    ]
                    transitions: [
                    Transition { NumberAnimation { properties: "width, height, opacity"; duration: 300; easing.type: Easing.InOutQuad } }
                    ]
                    }
                    }

                    GridView {
                        property int firstIndexDrag: -1
                    
                        id: grid
                        x: 0; y: 0
                        interactive: false
                    
                        anchors.rightMargin: 200
                        anchors.bottomMargin: 100
                        anchors.leftMargin: 200
                        anchors.topMargin: 100
                        anchors.fill: parent
                        cellWidth: 80; cellHeight: 80;
                    
                        model: WidgetModel { id: widgetmodel }
                        delegate: widgetdelegate
                        Item {
                            id: container
                            anchors.fill: parent
                        }
                        MouseArea {
                            id: coords
                            anchors.fill: parent
                            onReleased: {
                                if (grid.firstIndexDrag != -1)
                                    widgetmodel.move(grid.firstIndexDrag,grid.indexAt(mouseX, mouseY),1)
                                grid.firstIndexDrag = -1
                            }
                            onPressAndHold: {
                                grid.firstIndexDrag=grid.indexAt(mouseX, mouseY)
                            }
                        }
                    }
                    

                    }@

                    This has been made in to a Wiki Entry:
                    http://developer.qt.nokia.com/wiki/Drag_and_Drop_within_a_GridView

                    • Sacha
                    1 Reply Last reply Reply Quote 0
                    • D
                      Deqing last edited by

                      Hi Sacha,

                      The demo of drag and drop code looks cool!

                      I tried the code(Main2.qml) of second version in the wiki but failed with following error: "ReferenceError: Can't find variable: gridId"

                      Is there anything I can do to avoid this?

                      THanks

                      1 Reply Last reply Reply Quote 0
                      • X
                        xsacha last edited by

                        Well, I didn't write the second version.
                        I tested my (first) version and provided a video of that exact code running.

                        I can review the second one for you to discover the issue. It seems a lot better than my version so I hope you can get it working.

                        • Sacha
                        1 Reply Last reply Reply Quote 0
                        • B
                          baysmith last edited by

                          I'm responsible for the second version. I tried to update this post with a "I’ve updated the above wiki entry with an alternate implementation." like I did on the "other thread":http://developer.qt.nokia.com/forums/viewreply/14354/, but it failed for some reason.

                          As it turns out, the second version requires Qt 4.7.1. It gives that error with Qt 4.7.0. Thanks for pointing it out. I wasn't aware of this difference in the versions. I've updated the wiki page with a notation about this.

                          Nokia Certified Qt Specialist.

                          1 Reply Last reply Reply Quote 0
                          • X
                            xsacha last edited by

                            By the way, I just fixed in a critical issue with the first version in the wiki. It was to do with the moving code.
                            Problem was discovered and fixed in this thread: http://developer.qt.nokia.com/forums/viewthread/2460/P15/

                            The issue was that if you dragged items forward, the call to 'move' would push the indices backwards (to -1, -2 and so on) and you would no longer be able to drag the '-1' index and other items would become out of whack.

                            It is most noticeable on a 3-item grid.

                            I think the issue is only if you don't have animation onMove. The second example uses such an animation so it should be fine. Just be careful if you disable the animation.

                            • Sacha
                            1 Reply Last reply Reply Quote 0
                            • D
                              Deqing last edited by

                              Thank you guys. I finally get the second version working.

                              It turns out that "gridId" should be defined in WidgetModel.qml, and it must starts with 0. For example:

                              @
                              ListElement { icon: "images/widget1.png"; gridId: 0 }
                              ListElement { icon: "images/widget2.png"; gridId: 1 }
                              ListElement { icon: "images/widget3.png"; gridId: 2 }
                              @

                              1 Reply Last reply Reply Quote 0
                              • K
                                kyleplattner last edited by

                                Still returning:

                                @file:///Users/kp/Desktop/Precision Work/Screen Design/FinalScreens/QMLFinal/Rearrange4.qml:22: TypeError: Result of expression 'grid.items' [undefined] is not an object.@

                                1 Reply Last reply Reply Quote 0
                                • X
                                  xsacha last edited by

                                  I have made a cleaner version of the 'second version'
                                  Halved the lines of code, removed quite a lot of redundancy and doesn't require Qt4.7.1.
                                  Personally, I think the grids list is a bit silly when it can be done with the model/delegate. So I have completely removed the IconItem and grids.
                                  No loss of functionality.
                                  I replaced the first version with it. You can check it out in the wiki.

                                  • Sacha
                                  1 Reply Last reply Reply Quote 0
                                  • B
                                    baysmith last edited by

                                    The grids list was made because when I added behaviors in the delegate, it wasn't working. I don't know why it wasn't working for me, but what you've got is working. I'll remove the second version now that it is obsolete.

                                    Nokia Certified Qt Specialist.

                                    1 Reply Last reply Reply Quote 0
                                    • X
                                      xsacha last edited by

                                      Yeah, I know, you can't animate a GridList.
                                      I discussed this "in another thread.":http://developer.qt.nokia.com/forums/viewthread/2327/#13163

                                      Basically, you need to reparent the items within the delegate. Then you have complete freedom of movement and animation. I reparented the images to the MouseArea.

                                      • Sacha
                                      1 Reply Last reply Reply Quote 0
                                      • D
                                        Deqing last edited by

                                        Looks like in the new code the grid can't be resized, it always be 3*3.

                                        For example if I drag the size of its parent to a long list, it should be automatically rearranged to a 1*9 grid, as the GridView will do.

                                        1 Reply Last reply Reply Quote 0
                                        • X
                                          xsacha last edited by

                                          When you drag the window?
                                          Oh I had removed that as I was running it on a mobile device. I'll add that back in, thanks.

                                          • Sacha
                                          1 Reply Last reply Reply Quote 0
                                          • D
                                            Deqing last edited by

                                            Just get it works by simply set width and height of GridView equal to its parent. :)

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post