Как сделать элемент перетаскивания внутри круга в QML?


Приведенный ниже код позволяет перетащить небольшой прямоугольник красного цвета в область, которая является прямоугольником, определяемым минимальными и максимальными значениями сопротивления.

Я хочу, чтобы это продолжалось только до границы родительского прямоугольника, радиус которого равен 100, что означает, что теперь это круг.

Как сделать перетаскивание элемента внутри круга в QML?

Window {
    width: 200; height: 200; visible: true

    Rectangle
    {
        x: 10; y: 10
        width: 200; height: 200
        radius: 100
        color: "blue"

        Rectangle {
            x: 10; y: 10
            width: 20; height: 20
            color: "red"

            MouseArea
            {
                id: dragArea
                anchors.fill: parent

                drag.target: parent
                drag.minimumX : 20
                drag.maximumX : 150

                drag.minimumY : 20
                drag.maximumY : 150
            }
        }
    }
}
2 4

2 ответа:

Поэтому я нашел некоторое время, чтобы обеспечить вышеупомянутоеболее гладкое решение.

import QtQuick 2.5
import QtQuick.Window 2.2

Window {
    id: root
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    property int radius: 100

    Rectangle {
        id: circle
        width: 2 * radius
        height: 2 * radius
        radius: root.radius

        color: 'blue'
    }

    Rectangle {
        id: mark
        width: 20
        height: 20
        x: (dragObj.dragRadius <= root.radius ? dragObj.x : root.radius + ((dragObj.x - root.radius) * (root.radius / dragObj.dragRadius))) - 10
        y: (dragObj.dragRadius <= root.radius ? dragObj.y : root.radius + ((dragObj.y - root.radius) * (root.radius / dragObj.dragRadius))) - 10
        color: 'red'

        MouseArea {
            id: markArea
            anchors.fill: parent
            drag.target: dragObj
            onPressed: {
                dragObj.x = mark.x + 10
                dragObj.y = mark.y + 10
            }
        }
    }

    Item {
        id: dragObj
        readonly property real dragRadius: Math.sqrt(Math.pow(x - root.radius, 2) + Math.pow(y - root.radius, 2))
        x: root.radius
        y: root.radius

        onDragRadiusChanged: console.log(dragRadius)
    }
}

Я использую dragObj, чтобы избежать ограничений моей позиции перетаскивания. Это охватывает вектор от центра круга. Пока dragObj содержится в круге, я буду использовать его положение как положение маркера.
Но как только он покинет круг, я спроецирую вектор на круг, так что он останется в пределах.

Чтобы гарантировать, что каждое перетаскивание начинается снова на отметке я сброшу положение dragObj в положение метки, когда когда-либо мышь будет нажата снова (предварительное условие для нового события перетаскивания)

Получайте удовольствие от этого.

Немного опоздал,но мне нужно было кое-что проверить.

Вотнесовершенное решение, с некоторыми недостатками.

import QtQuick 2.5
import QtQuick.Window 2.2

Window {
    width: 400; height: 400; visible: true

    Rectangle
    {
        x: 10; y: 10
        width: 200; height: 200
        radius: 100
        color: "blue"

        Rectangle {
            x: 10; y: 10
            width: 20; height: 20
            color: "red"

            MouseArea
            {
                id: dragArea
                anchors.fill: parent

                drag.target: parent
                drag.minimumX : Math.ceil(100 - Math.sqrt(200 * parent.y - Math.pow(parent.y, 2)))
                drag.maximumX : Math.floor(Math.sqrt(200 * parent.y - Math.pow(parent.y, 2)) + 100)

                drag.minimumY : Math.ceil(100 - Math.sqrt(200 * parent.x - Math.pow(parent.x, 2)))
                drag.maximumY : Math.floor(Math.sqrt(200 * parent.x - Math.pow(parent.x, 2)) + 100)
            }
        }
    }
}
Идея состоит в том, что вы вычисляете максимальное и минимальное значения x и y в зависимости от текущего значения y и x (таким образом, max-x зависит от тока y, а max-y зависит от тока x)

Функция, стоящая за этим, является: (r - y)² + (r - x)² = r²

Что я не включил, так это размерность маленького перетаскиваемого прямоугольника. Поэтому я только заставляю верхний левый угол оставайтесь в пределах круга. Однако это должно быть легко адаптировано. Чтобы учесть это, предположим, что круг с половиной ширины/высоты прямоугольников меньше радиуса, и сдвинем его на половину ширины/высоты прямоугольников.

Другой недостаток заключается в том, что если я достигну одного из пределов (верхний, левый, правый, нижний), прямоугольник может мигать и не следовать за мышью плавно.

Чтобы исправить это, вы можете использовать невидимый объект в качестве помощника, который можно свободно рисовать вокруг, и затем использовать его положение чтобы вычислить положение красных прямоугольников, которое показано.

Возможно, я добавлю реализацию для этого позже. Я почти уверен, что это должно работать довольно гладко.