Как сделать элемент перетаскивания внутри круга в 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 ответа:
Поэтому я нашел некоторое время, чтобы обеспечить вышеупомянутоеболее гладкое решение.
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
в положение метки, когда когда-либо мышь будет нажата снова (предварительное условие для нового события перетаскивания)Получайте удовольствие от этого.
Немного опоздал,но мне нужно было кое-что проверить.
Вотнесовершенное решение, с некоторыми недостатками.
Идея состоит в том, что вы вычисляете максимальное и минимальное значения x и y в зависимости от текущего значения y и x (таким образом, max-x зависит от тока y, а max-y зависит от тока x)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) } } } }
Функция, стоящая за этим, является:
(r - y)² + (r - x)² = r²
Что я не включил, так это размерность маленького перетаскиваемого прямоугольника. Поэтому я только заставляю верхний левый угол оставайтесь в пределах круга. Однако это должно быть легко адаптировано. Чтобы учесть это, предположим, что круг с половиной ширины/высоты прямоугольников меньше радиуса, и сдвинем его на половину ширины/высоты прямоугольников.
Другой недостаток заключается в том, что если я достигну одного из пределов (верхний, левый, правый, нижний), прямоугольник может мигать и не следовать за мышью плавно.Чтобы исправить это, вы можете использовать невидимый объект в качестве помощника, который можно свободно рисовать вокруг, и затем использовать его положение чтобы вычислить положение красных прямоугольников, которое показано.
Возможно, я добавлю реализацию для этого позже. Я почти уверен, что это должно работать довольно гладко.