1) Rectangle에 Drag기능을 활성화한다.

2) DropArea에 이벤트별 상황을 설정한다.

3) DropArea에 마우스가 들어왔을때 확인을 위해 Rectangle을 포함시키고 색깔을 변경시킨다.

4) 이게 가장 중요한데 만약 Rectangle의 MouseArea에 onReleased: parent.Drag.drop()을 포함시키지 않는다면 드래그 & 드롭을 마치는 시점에 Drop이 아니라 Exit 이벤트가 발생한다. 그러므로 드롭이벤트를 발생시키려면 반드시 추가해야한다.

5) 또 다른 문제점은 DropArea와 Drag할 객체가 같은 스코프 안에 있어야 한다. 다른 스코프의 객체 내부의 DropArea에 접근하게 하려면 onDropped에 drop.accept()를 적어둬야 한다.

import QtQuick
import QtQuick.Controls

Window {
    visible: true
    width: 640
    height: 480

    DropArea {
        anchors.fill: parent
        onDropped: {
            console.log("onDropped");
            // drop.accept()
        }

        onEntered: {
            console.log("onEntered");
        }

        onExited: {
            console.log("onExited");
        }

        onPositionChanged: {
            console.log(drag.x + ' ' + drag.y);
        }

        Rectangle {
            anchors.fill: parent
            color: parent.containsDrag ? "green" : "yellow"
        }
    }

    Rectangle{
        width: 100
        height: 100
        x: 0
        y: 0
        color: "blue"

        MouseArea {
            id: dragArea1
            anchors.fill: parent
            drag.target: parent
            onReleased: parent.Drag.drop()
        }

        Drag.active: dragArea1.drag.active
        Drag.hotSpot.x: dragArea1.width / 2
        Drag.hotSpot.y: dragArea1.height / 2
    }
}

 

좀 더 발전시켜보면

1) 만약 DropArea 안에 떨어뜨리면 Accept가 출력된다. 반면 밖에 떨어뜨리면 Reject가 출력되면서 원래의 위치로 돌아간다.

2) Drag와 Drop에 keys를 부여해서 해당 드래그와 드롭에만 반응하게 만들 수 있다

import QtQuick
import QtQuick.Controls

Window {
    visible: true
    width: 640
    height: 480

    DropArea {
        id: droparea
        anchors.fill: parent
        keys: ["origin"]
        onDropped: {
            console.log("onDropped");
            drop.accept()
        }

        onEntered: {
            console.log("onEntered");
        }

        onExited: {
            console.log("onExited");
        }

        onPositionChanged: {
            console.log(drag.x + ' ' + drag.y);
        }
    }

    Rectangle{
        id: recta
        width: 100
        height: 100
        x: 100
        y: 200
        color: "blue"

        MouseArea {
            id: dragArea1
            anchors.fill: parent
            drag.target: parent
            acceptedButtons: Qt.AllButtons

            property int ori_x
            property int ori_y

            onPressed: {
                ori_x = recta.x;
                ori_y = recta.y;
                console.log(ori_x + ' ' + ori_y)
            }

            onReleased: {
                if (parent.Drag.drop() !== Qt.IgnoreAction)
                    console.log("Accepted.");
                else {
                    console.log("Rejected. Shifting to original place.");
                    recta.x = ori_x;
                    recta.y = ori_y;
                }
            }
        }

        Drag.active: dragArea1.drag.active
        Drag.hotSpot.x: dragArea1.width / 2
        Drag.hotSpot.y: dragArea1.height / 2
        Drag.keys: ["origin"]
    }
}

 

다른 방식으로 사용해보면 드래그해서 드롭하면 둘의 text가 서로 swap되게 만들 수 있게 됐다.

이게 어제 하루종일 구현해보고 싶었던 내용인데 하루 종일 해도 실패하다가 드디어 해냈다.

역시 결국은 구글과 스택오버플로우와 공식 도큐먼트다.

GPT와 코파일럿이 제 아무리 발전했다고 한들 어느정도 깊은 내용에 지엽적인 상황을 들이밀면 똑같은 말만 계속 되풀이한다.

결국 구글에서 스택오버플로우, qt forum을 보고 배우는게 훨씬 낫다

import QtQuick
import QtQuick.Controls

Window {
    visible: true
    width: 640
    height: 480

    Rectangle{
        id: rectangle1
        width: 100
        height: 100
        x: 0
        y: 200
        color: "blue"

        Text{
            id: text1
            anchors.fill: parent
            text: "BlueRect"
        }

        MouseArea {
            id: dragArea1
            anchors.fill: parent
            drag.target: parent
            acceptedButtons: Qt.AllButtons

            property int ori_x
            property int ori_y

            onPressed: {
                ori_x = rectangle1.x;
                ori_y = rectangle1.y;
                console.log(ori_x + ' ' + ori_y)
            }

            onReleased: {
                if (parent.Drag.drop() !== Qt.IgnoreAction) {
                    console.log("drag in");
                    var temp = text1.text;
                    text1.text = text2.text;
                    text2.text = temp;
                    rectangle1.x = ori_x;
                    rectangle1.y = ori_y;
                }
            }
        }

        Drag.active: dragArea1.drag.active
        Drag.hotSpot.x: dragArea1.width / 2
        Drag.hotSpot.y: dragArea1.height / 2

        DropArea {
            id: dropArea1
            anchors.fill: parent
            onDropped: {
                console.log("onDropped");
                drop.accept()
            }
        }
    }

    Rectangle{
        id: rectangle2
        width: 100
        height: 100
        x: 200
        y: 200
        color: "red"

        Text{
            id: text2
            anchors.fill: parent
            text: "RedRect"
        }

        MouseArea {
            id: dragArea2
            anchors.fill: parent
            drag.target: parent
            acceptedButtons: Qt.AllButtons

            property int ori_x
            property int ori_y

            onPressed: {
                ori_x = rectangle2.x;
                ori_y = rectangle2.y;
                console.log(ori_x + ' ' + ori_y)
            }

            onReleased: {
                if (parent.Drag.drop() !== Qt.IgnoreAction) {
                    console.log("drag in");
                    var temp = text1.text;
                    text1.text = text2.text;
                    text2.text = temp;
                    rectangle2.x = ori_x;
                    rectangle2.y = ori_y;
                }
            }
        }

        Drag.active: dragArea2.drag.active
        Drag.hotSpot.x: dragArea2.width / 2
        Drag.hotSpot.y: dragArea2.height / 2

        DropArea {
            id: dropArea2
            anchors.fill: parent
            onDropped: {
                console.log("onDropped");
                drop.accept()
            }
        }
    }
}

 

이제 위의 두개의 코드를 잘 섞어서 TaskManager 프로젝트에 두 내용을 변경하게 만들 수 있을 듯하다.