Search code examples
qmlqt6

QML Mouse areas are affected in separate zones


I created a frameless Window in QML and added multiple MouseArea and event handlers for moving and resizing it.
Initially, I only created the moving area and part of the resizing areas as a sample.

However, when I started, I noticed that events were only triggered for 3 out of the 4 areas, and they appeared to be intersecting despite not overlapping.
The cursor also changed in the correct place.

This problem occurred on both Linux and Windows.

What could be the reason for the active zones of different MouseArea intersecting, even though they should not?

To debug, I added a colored Rectangles for each MouseArea and increased their sizes."

I have also uploaded a sample video on Google Drive.

MyWin.qml

import QtQuick 6.2
import QtQuick.Controls 6.2

Window {
    id: win
    width: 200
    height: 100
    flags: Qt.FramelessWindowHint | Qt.Window
    property alias topPanel: topPanel

    Rectangle {
        anchors.fill: parent
        color: "#610161"

        Rectangle {
            id: topPanel
            z: 0
            height: 30
            color: "#4c4c4c"
            border.width: 0
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.top: parent.top
            anchors.rightMargin: 0
            anchors.leftMargin: 0
            anchors.topMargin: 0

            ActionButton {
                id: close
                width: 20
                height: 20
                anchors.right: parent.right
                anchors.top: parent.top
                z: 10
                image: "icons/close.svg"
                anchors.topMargin: 5
                anchors.rightMargin: 5
                backColor: "#00000000"

                Connections {
                    function onClicked() {
                        win.close()
                    }
                }
            }
        }
        MouseArea {
            id: moved
            z: 2

            Rectangle {
                anchors.fill: parent
                z: 32
                color: "#6a30e4"
            }

            property real lastX: 0
            property real lastY: 0
            x: 35
            y: 0
            anchors.left: lt.right
            anchors.right: topPanel.right
            anchors.top: topPanel.top
            anchors.bottom: topPanel.bottom
            anchors.rightMargin: 0
            anchors.bottomMargin: 0
            anchors.topMargin: 0
            anchors.leftMargin: 0
            Connections {
                target: moved
                function onPressed(mouse) {
                    console.debug("Pressed move", mouse.x, mouse.y, "MOVED:",
                                  moved.x, moved.y, "|", moved.width, "x",
                                  moved.height)
                    moved.lastX = mouse.x
                    moved.lastY = mouse.y
                    mouse.accepted = true
                }
                function onPositionChanged(mouse) {
                    mouse.accepted = true
                    let dx = (mouse.x - moved.lastX)
                    let dy = (mouse.y - moved.lastY)
                    console.debug("move dx:", dx, " dy:", dy, " mouse:",
                                  mouse.x, mouse.y, mouse.modifiers)
                    win.x += dx
                    win.y += dy
                }
            }
        }

        MouseArea {
            id: lbord
            z: 2
            width: 5
            anchors.top: lt.bottom
            anchors.left: parent.left
            anchors.bottom: lb.top
            anchors.topMargin: 0

            Rectangle {
                color: "#43ca28"
                anchors.fill: parent
                z: 32
            }
            property real lastX: 0
            property real lastY: 0
            Connections {
                target: lbord
                function onPressed(mouse) {
                    console.debug("Pressed lbord")
                    lbord.lastX = mouse.x
                }
                function onPositionChanged(mouse) {
                    let dx = (mouse.x - lbord.lastX)
                    console.debug("lbord dx:", dx, " lastX:", lbord.lastX,
                                  " mouse:", mouse.x, mouse.y)
                    win.x += dx
                    win.width -= dx
                    //                    lbord.lastX += dx
                }
            }
        }
        MouseArea {
            id: lb
            z: 2
            width: 15
            height: 15
            anchors.left: parent.left
            anchors.bottom: parent.bottom
            Rectangle {
                color: "#28cac7"
                anchors.fill: parent
                z: 32
            }

            property real lastX: 0
            property real lastY: 0
            Connections {
                target: moved
                function onPressed(mouse) {
                    console.debug("Pressed lb", mouse.x, mouse.y, "LB:", lb.x,
                                  lb.y, "|", lb.width, "x", lb.height)
                    lb.lastX = mouse.x
                    lb.lastY = mouse.y
                }
                function onPositionChanged(mouse) {
                    let dx = (mouse.x - lb.lastX)
                    let dy = (mouse.y - lb.lastY)
                    console.debug("lb dx:", dx, " dy:", dy, " mouse:", mouse.x,
                                  mouse.y, mouse.modifiers)
                    win.x += dx
                    win.y += dy
                    win.width -= dx
                    win.height += dy
                }
            }
        }
        MouseArea {
            id: lt
            z: 2
            width: 35
            height: 35
            anchors.left: parent.left
            anchors.top: parent.top
            cursorShape: Qt.SizeFDiagCursor
            Rectangle {
                color: "#eb1892"
                anchors.fill: parent
                z: 32
            }

            property real lastX: 0
            property real lastY: 0
            Connections {
                target: moved
                function onPressed(mouse) {
                    console.debug("Pressed lt", mouse.x, mouse.y, "LT:", lt.x,
                                  lt.y, "|", lt.width, "x", lt.height)
                    lt.lastX = mouse.x
                    lt.lastY = mouse.y
                }
                function onPositionChanged(mouse) {
                    let dx = (mouse.x - lt.lastX)
                    let dy = (mouse.y - lt.lastY)
                    console.debug("lt dx:", dx, " dy:", dy, " mouse:", mouse.x,
                                  mouse.y, mouse.modifiers)
                    win.x += dx
                    win.y += dy
                    win.width -= dx
                    win.height -= dy
                }
            }
        }
    }
}

A video showing the bugs Google Drive


Solution

  • You signal handler function are triggered in 3 out of 4 of your Connections objects because you assigned the same target for 3 of them.

    You don't even have to use Connections since you are the one instantiating your MouseArea:

    MouseArea {
        id: mouseArea
        Connections {
            target: mouseArea
            function onPressed(mouse) { ... }
        }
    }
    

    Is the equivalent of

    MouseArea {
        onPressed(mouse) { ... }
    }
    

    Also I would advise to use startSystemMove and startSystemResize.