首页 文章

在Qml中拖放多个项目

提问于
浏览
0

我需要在我的应用程序中绘制一堆矩形 . 用户应该能够单独选择它们并自由移动它们并改变它们的位置 . 用户还应该能够选择多个矩形并同时移动所有选定的矩形并将其释放到其他位置 . 我已经可以实现一些基于Gridview的东西,它可以处理一个Rectangle的选择和移动,但是我不能让它适用于多个选择/移动 . 这是我目前的一段代码:

GridView { 
        id: mainGrid
        cellWidth: 7;
        cellHeight: 7;

        ListModel {
            id: myModel
            function createModel() {
                for(var i = 0; i < totalZoneList.length; i++)
                {
                    for (var j = 0; j < moduleZoneList.length; j++)
                    {
                         myModel.append({"item1": ITEM1, "item2": ITEM2})
                    }
                }
            }
            Component.onCompleted: {createModel()}
        }

        Component { 
            id: myblocks
            Item {
                id: item
                width: mainGrid.cellWidth; 
                height: mainGrid.cellHeight;
                Rectangle {
                    id: box
                    parent: mainGrid
                    x: //CALCULATED BASED ON MODEL
                    y: //CALCULATED BASED ON MODEL
                    width: //CALCULATED BASED ON MODEL
                    height: //CALCULATED BASED ON MODEL


                    MouseArea {
                        id: gridArea
                        anchors.fill: parent
                        hoverEnabled: true
                        drag.axis: Drag.XandYAxis
                        drag.minimumX: 0
                        drag.minimumY: 0


                        property int mX: (mouseX < 0) ? 0 : ((mouseX < mainGrid.width - mainGrid.cellWidth) ? mouseX : mainGrid.width - mainGrid.cellWidth)
                        property int mY: (mouseY < 0) ? 0 : ((mouseY < mainGrid.height - mainGrid.cellHeight) ? mouseY : mainGrid.height - mainGrid.cellHeight)
                        property int index: parseInt(mX/mainGrid.cellWidth) + 5*parseInt(mY/mainGrid.cellHeight)  //item underneath cursor
                        property int activeIndex
                        property var xWhenPressed
                        property var yWhenPressed
                        propagateComposedEvents: true

                        onPressed: {
                            activeIndex = index
                            drag.target = box
                            xWhenPressed = box.x
                            yWhenPressed = box.y

                            gridArea.drag.maximumX = mainGrid.width - box.width
                            gridArea.drag.maximumY = mainGrid.height - box.height
                        }
                        onReleased: {
                           if(xWhenPressed !== box.x || yWhenPressed !== box.y)
                            {
                              //RECALCULATE THE POSITION
                            }
                        }
                        onPositionChanged: {
                            if (drag.active && index !== -1 && index !== activeIndex) {
                                                            mainGrid.model.move(activeIndex, activeIndex = index, 1)
                            }
                        }
                    } // Mousearea
                } // Rectangle
            } // Item
        } // Component

    } //mainGrid

2 回答

  • 1

    我没有让你的代码工作 . 首先,我看到错误:

    Rectangle {
        id: box
        parent: mainGrid
    ...
    }
    

    你只需要删除没有用的父 Item ,并将 Rectangle 设置为委托的根 .

    然后,你忘了提到拖动的目标是 Rectangle

    drag.target: parent
    

    这是纠正后的代码:

    Component {
        id: myblocks
    
        Rectangle {
            id: box
            color: "red"
            width: 20
            height: 20
    
            MouseArea {
                id: gridArea
                anchors.fill: parent
                drag.target: parent
                hoverEnabled: true
                drag.axis: Drag.XandYAxis
            } // Mousearea
        } // Rectangle
    } // Component
    

    然后,您不应该使用 GridView 因为您想要移动元素 . 如果您使用 Repeater 它可以工作,您只需在 Rectangle 中设置 xy 就可以将元素放在开头 .

    现在,这是您的问题的解决方案:您单击一个元素以选择它,您可以一次移动所有选定的项目 .

    Window {
        visible: true
        width: 640
        height: 480
    
        property var totalZoneList: ["total1", "total2"]
        property var moduleZoneList: ["module1", "module2"]
    
        Repeater{
            id: iRepeater
            model: ListModel {
                        id: myModel
                        function createModel() {
                            for(var i = 0; i < totalZoneList.length; i++)
                            {
                                for (var j = 0; j < moduleZoneList.length; j++)
                                {
                                    myModel.append({"item1": totalZoneList[i], "item2": moduleZoneList[j]})
                                }
                            }
                        }
                        Component.onCompleted: {createModel()}
                    }
            delegate: myblocks
    
        }
    
        Component {
            id: myblocks
    
            Rectangle {
                id: box
                color: {
                    switch(index){
                    case 0: selected ? "red" : "#FF9999";break;
                    case 1: selected ? "blue" : "lightblue";break;
                    case 2: selected ? "green" : "lightgreen";break;
                    case 3: selected ? "grey" : "lightgrey";break;
                    }
                }
                x: (width + 5)*index
    
                width: 20
                height: 20
                property int offsetX:0
                property int offsetY:0
                property bool selected: false
                function setRelative(pressedRect){
                    disableDrag();
                    x = Qt.binding(function (){ return pressedRect.x + offsetX; })
                    y = Qt.binding(function (){ return pressedRect.y + offsetY; })
                }
                function enableDrag(){
                    gridArea.drag.target = box
                }
                function disableDrag(){
                    gridArea.drag.target = null
                }
    
                MouseArea {
                    id: gridArea
                    anchors.fill: parent
                    hoverEnabled: true
                    drag.axis: Drag.XandYAxis
                    onClicked: parent.selected=!parent.selected
    
                    onPressed: {
    
                        var pressedRect = iRepeater.itemAt(index);
                        if (pressedRect.selected == true){
                            for (var i=0; i<iRepeater.count; i++ ){
                                var rect = iRepeater.itemAt(i);
                                if (i != index){
                                    //init for breaking existing binding
                                    rect.x = rect.x
                                    rect.y = rect.y
                                    rect.disableDrag()
                                    if (rect.selected == true){
                                        rect.offsetX = rect.x - pressedRect.x
                                        rect.offsetY = rect.y - pressedRect.y
                                        rect.setRelative(pressedRect)
                                    }
                                }
                            }
                            pressedRect.enableDrag()
                        }
                    }
                } // Mousearea
            } // Rectangle
        } // Component
    }
    
  • 2

    食谱一:

    • 使用 Repeater ,因此定位不是由视图决定,而是由您自己决定 .

    • 使用隐形助手 Item . 这是你的 drag.target .

    • 实施您选择对象的首选方式 - 通过单击天气或绘图框并检查此框中包含的对象 . 使所有选定对象的位置相对于不可见的辅助对象 .

    • 拖动辅助对象,并相应地移动所有其他对象 .

    • 完成后,再次取消选择对象并使其位置绝对(在父坐标系内)

    食谱二:

    • 将所有选定对象重新显示为新项目,同时相应地映射其坐标

    • 移动新项目

    • 将所有对象重新归还原始画布,将其坐标重新映射回来 .


    我希望这足以解决您的问题(据我所知)如果它解决了另一个问题,那么您需要更具体地说明拖拽对象的预期行为 .

相关问题