Search code examples
qtuser-interfaceqmlqtquick2

Prevent Flickable movement when interacting with TextField


I have a qml TextField on top of a Flickable. If I press the mouse down on the TextField and move the mouse, the Flickable will move with it. This can interfere with behavior such as text highlighting. How can I prevent moving/dragging the Flickable when I click/drag in the TextField?

Reproducible example:

import QtQuick 6.5
import QtQuick.Controls 6.5

Rectangle {
    id: window
    width: 800
    height: 600

    Flickable {
        anchors.fill: parent
        contentWidth: 2000
        contentHeight: 2000

        Rectangle {
            anchors.fill: parent
            color: "white"

            Rectangle {
                width: 400
                height: 400
                anchors.centerIn: parent
                color: "black"
                
                TextField {
                    width: 100
                    anchors.centerIn: parent
                    background: Rectangle {
                        color: "gray"
                    }
                }
            }
        }

        Component.onCompleted: {
            contentX = contentWidth / 2.0 - window.width / 2.0
            contentY = contentHeight / 2.0 - window.height / 2.0
        }
    }
}

What I tried:
Using preventStealing in a MouseArea in the TextField does prevent the Flickable from moving but it also prevents me from clicking or entering text into the TextField and stops the cursor from changing on hover.

TextField {
    anchors.centerIn: parent

    MouseArea {
        anchors.fill: parent
        preventStealing: true
    }
}

I also came across setKeepMouseGrab and setKeepTouchGrab in C++ which seem to do what I want if set to true. However, I do not want to try inheriting from the private TextField implementation or creating my own custom version of TextField just to set these flags. I can not find a way to set them from QML.

How can I fix this input conflict?
I am running Ubuntu 22.10 with Wayland.


Solution

  • You can assign a DragHandler to TextField, e.g.

    Flickable {
        TextField {
            DragHandler { }
        }
    }
    

    Alternatively, you could disable Flickable interactive whenever the TextField gets focus, e.g.

    Flickable {
        interactive: !textField.focus
        TextField {
            id: textField
        }
    }