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. Drag a proxy (drag.target) out of a clipped sub view
Qt 6.11 is out! See what's new in the release blog

Drag a proxy (drag.target) out of a clipped sub view

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
3 Posts 1 Posters 3.9k 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.
  • ? Offline
    ? Offline
    A Former User
    wrote on last edited by A Former User
    #1

    I must say I am enjoying QtQuick a fair bit and I am making good progress. However, I have stumbled accross another puzzler. I hope the example is not getting too complicated, but I want to provide some context as to what I am trying to do and have self-contained code.

    Essentially, I have my StackView working perfectly now, allowing me to browse through different ListViews. Now, my problem is that I would like each item in those ListViews to have a handle, which can be used to drag ListItems via proxy from the ListView into another View (e.g. let's say a shopping basket). However, since the proxy is defined as a child, it is getting clipped by the ancestor Rectangle. Now, please note that the appearance of the proxy depends on the Item from which the drag was initiated, so I cannot simply avoid the problem by making one "global" proxy. Conceptually, each ListItem should have its own proxy.

    import QtQuick 2.5
    import QtQuick.Controls 1.4
    import QtQuick.Window 2.2
    
    Window {
        id: root
        width: 800; height: 600
        visible: true
    
        ListModel {
            id: fruitModel
    
            ListElement {
                title: "Apple"
                elementColor: "green"
            }
            ListElement {
                title: "Orange"
                elementColor: "orange"
            }
            ListElement {
                title: "Banana"
                elementColor: "yellow"
            }
        }
    
        ListView {
            id: fruitList
            model: fruitModel
            delegate: Item {
                width: parent.width; height: 80
                Rectangle {
                    anchors.fill: parent
                    color: "lightblue"
                    Text {
                        anchors.fill: parent
                        color: "black"
                        text: title
                    }
                    Rectangle
                    {
                        id: dragHandle
                        anchors.right: parent.right
                        anchors.rightMargin: 10
                        width: 60; height: 60
                        color: elementColor
    
                        MouseArea {
                            id: dragArea
                            anchors.fill: parent
    
                            drag.target: dragProxy
    
                            Rectangle
                            {
                                id: dragProxy
                                width: 60; height: 60
                                color: elementColor
    
                                //Drag.active: parent.drag.active
    
                                Drag.dragType: Drag.Automatic
    
                                property bool dragActive: dragArea.drag.active
    
                                onDragActiveChanged: {
                                    if (dragActive) {
                                        console.log("started")
                                        Drag.start();
                                    } else {
                                        console.log("finished")
                                        // Reset position for next drag
                                        dragProxy.x = dragArea.x;
                                        dragProxy.y = dragArea.y;
                                        Drag.drop();
                                    }
                                }
                                visible: parent.drag.active
                            }
                        }
                    }
                }
            }
            visible: false
        }
    
        Item {
            anchors.top: aTitleBar.bottom; anchors.left: aTitleBar.left
            width: 300; height: 480
            clip: true
    
            StackView {
                id: aStackView
                anchors.fill: parent
    
                initialItem: Rectangle {
                    color: "lightblue"
                    Text {
                        anchors.fill: parent
                        color: "black"
                        text: "Fruit"
                    }
                    MouseArea {
                        id: mouse
                        anchors.fill: parent
                        onClicked: aStackView.push({ item: fruitList, properties: { text: title, color: color }})
                    }
                }
            }
        }
    
        Rectangle {
            id: aTitleBar
            x: 50; y: 20
            width: 300; height: 80
            color: "darkblue"
            Text {
                anchors.fill: parent
                color: "white"
                text: "Store"
            }
            MouseArea {
                anchors.fill: parent
                onClicked: aStackView.pop()
            }
        }
    
        Rectangle {
            id: aBasket
            x: 450; y: 20
            width: 300; height: 560
            color: "lightblue"
            Text {
                anchors.fill: parent
                color: "black"
                text: "Basket"
            }
            DropArea {
                anchors.fill: parent
                onEntered: console.log("entered")
                onExited: console.log("exited")
                onDropped: console.log("dropped")
            }
        }
    }
    

    Any suggestions on how to proceed?

    1 Reply Last reply
    0
    • ? Offline
      ? Offline
      A Former User
      wrote on last edited by
      #2

      Ok, maybe the example was a bit too complicated. Here is a simplified version:

      import QtQuick 2.5
      import QtQuick.Controls 1.4
      import QtQuick.Window 2.2
      
      Window {
          id: root
          width: 800; height: 600
          visible: true
      
          Rectangle {
              id: aDragSource
              x: 50; y: 20
              width: 300; height: 560
              color: "lightblue"
      
              clip: true
      
              Text {
                  anchors.fill: parent
                  color: "black"
                  text: "Source"
              }
      
              Rectangle
              {
                  id: aDragHandle
                  anchors.right: parent.right
                  anchors.rightMargin: 10
                  width: 60; height: 60
                  color: "red"
      
                  MouseArea {
                      id: aDragArea
                      anchors.fill: parent
      
                      drag.target: aDragProxy
      
                      Rectangle
                      {
                          id: aDragProxy
                          width: 60; height: 60
                          color: "red"
      
                          //Drag.active: parent.drag.active
      
                          Drag.dragType: Drag.Automatic
      
                          property bool dragActive: aDragArea.drag.active
      
                          onDragActiveChanged: {
                              if (dragActive) {
                                  console.log("started")
                                  Drag.start();
                              } else {
                                  console.log("finished")
                                  // Reset position for next drag
                                  aDragProxy.x = aDragArea.x;
                                  aDragProxy.y = aDragArea.y;
                                  Drag.drop();
                              }
                          }
                          visible: parent.drag.active
                      }
                  }
              }
          }
      
          Rectangle {
              id: aDropTraget
              x: 450; y: 20
              width: 300; height: 560
              color: "lightblue"
      
              Text {
                  anchors.fill: parent
                  color: "black"
                  text: "Target"
              }
      
              DropArea {
                  anchors.fill: parent
                  onEntered: console.log("entered")
                  onExited: console.log("exited")
                  onDropped: console.log("dropped")
              }
          }
      }
      

      This illustrates the basic problem. Ideally, I would like to define the proxy locally as is, but have it rendered on top of the scene and not be clipped by any of its ancestors. For more on the motivation behind this, have a look at the first example. Any feedback/help would be very much appreciated!

      1 Reply Last reply
      0
      • ? Offline
        ? Offline
        A Former User
        wrote on last edited by
        #3

        Well, this is proving much more difficult than I had expected. Since all my attempts to solve the problem in a declarative way have failed, I turned to programmatically creating the proxy element:

        import QtQuick 2.5
        import QtQuick.Controls 1.4
        import QtQuick.Window 2.2
        
        Window {
            id: window
            width: 800; height: 600
            visible: true
        
            Item
            {
                id: root
                anchors.fill: parent
        
                Rectangle {
                    id: aDropTraget
                    x: 450; y: 20
                    width: 300; height: 560
                    color: "lightblue"
        
                    Text {
                        anchors.fill: parent
                        color: "black"
                        text: "Target"
                    }
        
                    DropArea {
                        anchors.fill: parent
                        onEntered: console.log("entered")
                        onExited: console.log("exited")
                        onDropped: {
                            console.log(drop.hasText, drop.text)
                            console.log("dropped")
                        }
                    }
                }
        
                Rectangle
                {
                    id: aDragHandle
                    x: 10; y: 80
                    width: 60; height: 60
                    color: "red"
        
                    MouseArea {
                        id: aDragArea
                        anchors.fill: parent
        
                        property var dragComponent: null
                        property var dragProxy: null
        
                        function moveProxy(mouse) {
                            var pos = root.mapFromItem(aDragHandle, mouse.x, mouse.y);
                            dragProxy.x = pos.x - dragProxy.height/2;
                            dragProxy.y = pos.y - dragProxy.width/2;
                        }
        
                        onPressed: {
                            if (!dragProxy) {
                                dragProxy = dragComponent.createObject(root, { "width": aDragHandle.width, "height": aDragHandle.height, "color": "orange" });
                                dragProxy.Drag.mimeData = { "text/plain": "Hello Drag!" };
                            }
        
                            dragProxy.Drag.start();
                            moveProxy(mouse);
                        }
        
                        onPositionChanged: {
                            moveProxy(mouse);
                        }
        
                        onReleased: {
                            moveProxy(mouse);
                            dragProxy.Drag.drop();
        
                            if (dragProxy) {
                                dragProxy.destroy();
                                dragProxy = null;
                            }
                        }
        
                        Component.onCompleted: {
                            dragComponent = Qt.createComponent("controls/DragProxy.qml");
                            if (dragComponent.status === Component.Error) {
                                console.log("Error creating drag component.");
                                console.log(dragComponent.errorString());
                            }
                        }
                    }
                }
            }
        }
        

        At first, this almost looks like it is working. However, the mime data is always empty, which means there is no way to send any information to the DropArea, rendering the whole thing useless. I am honestly at the end of my wits here...

        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