Drag & Drop in QtQuick (QML) Applications

Last edited on

Synopsis

For the most cases of Drag & Drop between Objects the dragAnDrop function is the best approach.

If desired, Drag & drop can also be synthesized via mousePress(), mouseMove() and mouseRelease().

However, to initiate a drag or a drop, the mouse cursor must be moved in small steps over a minimum distance. The following is an example that demonstrates how to achieve that.

Python

import names

def main():
    startApplication("my_qtquick_drag_and_drop_application")

    # Drag & drop at offset from top-left corner of the
    # source and target objects:
    startDragQtQuick(waitForObject(names.Text), 5, 5)
    dropOnQtQuick(waitForObject(names.dropRectangle_Rectangle), 5, 5)

    # Drag & drop at center of the source and target objects:
    startDragQtQuick(waitForObject(names.Text))
    dropOnQtQuick(waitForObject(names.dropRectangle_Rectangle))

    snooze(1)


def startDragQtQuick(obj, obj_top_left_x_offset=None, obj_top_left_y_offset=None):
    if obj_top_left_x_offset is None or obj_top_left_y_offset is None:
        mousePress(obj)
    else:
        if obj_top_left_x_offset is None:
            obj_top_left_x_offset = 1
        if obj_top_left_y_offset is None:
            obj_top_left_y_offset = 1
        mousePress(obj, obj_top_left_x_offset, obj_top_left_y_offset, MouseButton.LeftButton)
    triggerDragDrop(obj, obj_top_left_x_offset, obj_top_left_y_offset)


def dropOnQtQuick(obj, obj_top_left_x_offset=None, obj_top_left_y_offset=None):
    triggerDragDrop(obj, obj_top_left_x_offset, obj_top_left_y_offset)
    mouseRelease(MouseButton.LeftButton)


def triggerDragDrop(obj, obj_top_left_x_offset=None, obj_top_left_y_offset=None):
    # https://doc.qt.io/squish/squish-api.html#object-globalbounds-function
    # https://doc.qt.io/squish/squish-api.html#rgss-screenrectangle-object
    rect = object.globalBounds(obj)

    x = rect.x
    # At center if no offset provided:
    if obj_top_left_x_offset is None:
        x = rect.center().x
    else:
        # At provided offset:
        x = x + obj_top_left_x_offset

    y = rect.y
    # At center if no offset provided:
    if obj_top_left_y_offset is None:
        y = rect.center().y
    else:
        # At provided offset:
        y = y + obj_top_left_y_offset

    # delta is the drag distance in pixels; if
    # too small no drag/drop may take place:
    delta = 10

    # Some snooze() to visually follow
    # the activity:
    st = 0.01

    for i in range(delta):
        mouseMove(x+i, y)
        snooze(st)
    for i in range(delta):
        mouseMove(x, y+i)
        snooze(st)
    for i in range(delta):
        mouseMove(x-i, y)
        snooze(st)
    for i in range(delta):
        mouseMove(x, y-i)
        snooze(st)
    mouseMove(x, y)
test.py