How to make an item drag inside a circle in QML?

前端 未结 2 1462
自闭症患者
自闭症患者 2021-02-10 15:08

Below code allows the small red coloured rectangle to be dragged in an area which is a rectangle defined by minimum and maximum drag values.

I want it to go on only up t

相关标签:
2条回答
  • 2021-02-10 15:55

    So I found some time to provide the aforementioned smoother solution.

    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)
        }
    }
    

    I use the dragObj to avoid the limitations of my dragging position. This spans a vector from the center of the circle. As long as the dragObj itself is contained in the circle, I will use it's position as the position of the marker.
    But once it leaves the circle, I will project the vector on the circle, so it will stay within the limits.

    To ensure, that every drag starts again on the mark, I will reset the position of the dragObj to the position of the mark, when ever the mouse is pressed again (precondition for a new drag-event)

    Have fun with it.

    0 讨论(0)
  • 2021-02-10 16:12

    A little bit late, but I was up for some quiz.

    Here is a imperfect solution, with some flaws.

    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)
                }
            }
        }
    }
    

    The idea is, that you calculate the max- and min-values of x and y depending on the current value of y and x (so max-x is depending on current-y, and max-y is depending on current-x)

    The function behind that is: (r - y)² + (r - x)² = r²

    What I did not incorporate is the dimension of the small draggable Rectangle. So I only force the top-left corner to stay within the circles bounds. This however should be easy to adapt. To account for that, assume a circle, with half the rectangles width/height less radius, and shift it by half the rectangles width/height.

    Another flaw is, that if I reach one of the limits (top, left, right, bottom) the Rectangle might flicker and does not follow the mouse smoothly.

    To fix that, you can use an invisible object as helper, that can be freely drawn around, and you then use it's position to calculate the red Rectangles position that is shown.

    Maybe I will add an implementation for that later as well. I am pretty sure, this should work pretty smoothly.

    0 讨论(0)
提交回复
热议问题