2016-10-05 81 views
0

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

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

我没有设法让您的代码正常工作。首先,我看到它的错误:

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 
} 
+0

感谢您的回复,但我不明白如何可以帮助移动多个项目。正如我所说,我不想移动所有的矩形。有时候只是其中的一个,有时也是其中的一个子集! –

+0

我已经测试过你的解决方案,它不起作用! –

+0

我编辑了帖子 – user2436719

1

配方一:

  1. 使用Repeater,所以定位不是由一个观点,但自己决定。

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

  3. 实现您的首选方式选择您的对象 - 天气通过单击,或绘制框和执行检查哪些对象包括在此框中。使所有选定对象的位置相对于您的隐形助手对象。

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

  5. 完成后,再取消选择对象,使它们的位置绝对(父母中的坐标系)

配方二:

  1. 重新设置父级所有选择的对象到一个新的项目,同时映射其坐标

  2. 移动新项目

  3. 将所有对象重新绘制回原始画布,并将其坐标映射回原来的位置。


我希望这是足以解决你的问题(据我的理解是) 如果它解决了另一个问题,比你需要更具体的关于您的draged对象的预期行为。