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. [Solved] QML and Drag and Drop

[Solved] QML and Drag and Drop

Scheduled Pinned Locked Moved QML and Qt Quick
42 Posts 8 Posters 38.3k 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.
  • X Offline
    X Offline
    xsacha
    wrote on last edited by
    #4

    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
    0
    • K Offline
      K Offline
      kyleplattner
      wrote on last edited by
      #5

      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
      0
      • X Offline
        X Offline
        xsacha
        wrote on last edited by
        #6

        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
        0
        • K Offline
          K Offline
          kyleplattner
          wrote on last edited by
          #7

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

          1 Reply Last reply
          0
          • X Offline
            X Offline
            xsacha
            wrote on last edited by
            #8

            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
            0
            • D Offline
              D Offline
              Deqing
              wrote on last edited by
              #9

              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
              0
              • X Offline
                X Offline
                xsacha
                wrote on last edited by
                #10

                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
                0
                • B Offline
                  B Offline
                  baysmith
                  wrote on last edited by
                  #11

                  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
                  0
                  • X Offline
                    X Offline
                    xsacha
                    wrote on last edited by
                    #12

                    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
                    0
                    • D Offline
                      D Offline
                      Deqing
                      wrote on last edited by
                      #13

                      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
                      0
                      • K Offline
                        K Offline
                        kyleplattner
                        wrote on last edited by
                        #14

                        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
                        0
                        • X Offline
                          X Offline
                          xsacha
                          wrote on last edited by
                          #15

                          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
                          0
                          • B Offline
                            B Offline
                            baysmith
                            wrote on last edited by
                            #16

                            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
                            0
                            • X Offline
                              X Offline
                              xsacha
                              wrote on last edited by
                              #17

                              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
                              0
                              • D Offline
                                D Offline
                                Deqing
                                wrote on last edited by
                                #18

                                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
                                0
                                • X Offline
                                  X Offline
                                  xsacha
                                  wrote on last edited by
                                  #19

                                  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
                                  0
                                  • D Offline
                                    D Offline
                                    Deqing
                                    wrote on last edited by
                                    #20

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

                                    1 Reply Last reply
                                    0
                                    • X Offline
                                      X Offline
                                      xsacha
                                      wrote on last edited by
                                      #21

                                      Yeah it already does that.
                                      Anchor is fill to parent and parent width is whatever the host operating system gives it. 640x480 is just for reference.
                                      Try it out now?
                                      I think the qmlviewer on Windows won't allow you to resize the window smaller than 640x480 by the way. Might need a custom qmlviewer for that.

                                      • Sacha
                                      1 Reply Last reply
                                      0
                                      • D Offline
                                        D Offline
                                        Deqing
                                        wrote on last edited by
                                        #22

                                        As I can see, the size of qmlViewer will be the same as the top item in the qml file when it starts.

                                        Now I'm thinking of storing position of these icons.

                                        I guess the position should be stored in the model(or somewhere else?). How to show icons in GridView according to the values stored in the model?

                                        1 Reply Last reply
                                        0
                                        • X Offline
                                          X Offline
                                          xsacha
                                          wrote on last edited by
                                          #23

                                          Well you actually cannot change the positions of items inside a GridView.

                                          What I have done is created items within the GridView and then reparented them to a MouseArea (outside of GridView) so that I can move them freely.
                                          Then I assign the x,y values of the GridView locations.

                                          If you were to create entirely new locations and not use a GridView at all, you may as well use a Flow element.

                                          If you're just using GridView/ListView for the model/delegate, then I will answer your question:

                                          In your model, create an 'x' and 'y' property. For example 'myx', 'myy'. Then in the image, just set:
                                          @x=myx; y=my@

                                          • Sacha
                                          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