Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to implement “Snap While Dragging” behavior in QML?



  • I'm looking to achieve a "snap while dragging" behavior in QML. Specifically, within my example below, when the element being dragged (red column) reaches a location on the x axis that is inside the "snap area" (orange column), it snaps to the middle of the snap area and sticks there until the mouse pointer is again outside the snap area, at which point the dragged element should snap to the current position of the mouse pointer and the drag continues on it's way. Here is what I have so far:

    import QtQuick 2.12
    import QtQuick.Window 2.12
    
    Window {
        id: main_window
        width: 640
        height: 480
        visible: true
        visibility: Window.Maximized
    
        property double x_location: square.x
        property double y_location: square.y
    
        property double start_x_of_snap_area: snap_area.x
        property double end_x_of_snap_area: snap_area.x + snap_area.width
    
        property bool is_handlebar_inside_snap_area: false
    
        onX_locationChanged: function () {
            if (x_location >= start_x_of_snap_area
                    && square.x + square.width <= end_x_of_snap_area) {
                is_handlebar_inside_snap_area = true
            } else {
                is_handlebar_inside_snap_area = false
            }
        }
    
        onIs_handlebar_inside_snap_areaChanged: function () {
            if (is_handlebar_inside_snap_area === true) {
                console.log(dragArea.drag.target)
                dragArea.drag.target = null
                square.anchors.horizontalCenter = snap_area.horizontalCenter
            }
        }
    
        Text {
            y: 0
            text: "start_x_of_snap_area: " + start_x_of_snap_area
            font.pixelSize: 30
        }
    
        Text {
            y: 50
            text: "end_x_of_snap_area: " + end_x_of_snap_area
            font.pixelSize: 30
        }
    
        Text {
            y: 100
            text: "is_handlebar_inside_snap_area: " + is_handlebar_inside_snap_area
            font.pixelSize: 30
        }
    
        Rectangle {
            id: snap_area
            height: parent.height
            width: 200
            anchors.centerIn: parent
            color: 'orange'
    
            Text {
                text: "snap area"
                font.pixelSize: 30
                anchors.centerIn: parent
            }
        }
    
        Rectangle {
            id: square
            width: 50
            height: main_window.height
            color: 'red'
            opacity: .7
            Drag.active: dragArea.drag.active
    
            Text {
                text: 'x: ' + x_location + ' y: ' + y_location
                font.pixelSize: 10
                color: 'white'
                anchors.centerIn: parent
                font.family: 'Arial'
            }
    
            MouseArea {
                id: dragArea
                drag {
                    target: parent
                    axis: "XAxis"
                    minimumX: 0
                    maximumX: main_window.width - square.width
                }
                anchors.fill: parent
                cursorShape: Qt.SizeAllCursor
            }
        }
    }
    

    Some problems with the above code is once the snap happens, its stuck. Also, if you move the mouse pointer really fast over the snap area the function doesn't fire quick enough to give satisfactory results (it doesn't work at all).


Log in to reply