如何在QML中使一个物品在圆形内拖动?

4
以下代码允许小的红色矩形在一个由最小和最大拖曳值定义的矩形区域中被拖曳。
我希望它仅限于在父级矩形边界内拖动,其半径为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
不确定拖放属性是否接受函数。如果可以,您可以轻松设置正弦/余弦值。 - Sebastian Lange
你需要测试父矩形的所有4个顶点是否在圆内。半径是它们可以到达的最大长度从中心开始计算。尝试使用以下公式:Math.pow((x - center_x),2) + Math.pow(y - center_y,2)) < Math.pow(r,2) - folibis
2个回答

5

我找到了一些时间,提供上述更加流畅的解决方案。

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的位置为标记的位置。
祝你玩得开心。

我们能否让它只沿半径拖动? - George Thomas
@GeorgeThomas:你的意思是什么:它应该始终保持在半径上,永远不会在圆圈内,还是标记的角落不应该越过边界?两者都是可能的。前者相当容易,后者则稍微复杂一些。 - derM
在第一个方法中,它应该沿半径移动。不应该进入或离开。 - George Thomas
id: markRectangle 中,存在对 xy 的条件。只考虑当它求值为 false 时的情况(将 x 设置为 root.radius + ((dragObj.x - root.radius) * (root.radius / dragObj.dragRadius))) - 10)。 - derM

1
有点晚了,但我想做一些小测试。
这是一个不完美的解决方案,有一些缺陷。
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)
            }
        }
    }
}

这个想法是,根据当前的y和x值计算出x和y的最大和最小值(因此max-x取决于current-y,而max-y取决于current-x)。
背后的函数是: (r-y)²+(r-x)²=r²
我没有考虑到小可拖动矩形的尺寸。所以我只强制左上角保持在圆形范围内。然而,这应该很容易适应。为了解决这个问题,可以假设一个圆,半径减去矩形宽度/高度的一半,并将其移动矩形宽度/高度的一半。
另一个缺陷是,如果达到了极限(顶部、左侧、右侧、底部),矩形可能会闪烁,而且不会平滑地跟随鼠标。
要解决这个问题,可以使用一个无形的助手对象,可以自由绘制,然后使用它的位置来计算所显示的红色矩形的位置。
也许以后我会添加一个实现。我相信,这应该能够非常流畅地工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接