1
votes

I have two rectangles and i want them to send mouseevent to each other while moving mouse with pressed mouse button. See my example

Rectangle {
    x: 100
    width: 30
    height: 30
    color: "red"
    MouseArea {
        hoverEnabled: true
        propagateComposedEvents: true

        anchors.fill: parent
        onMouseXChanged: console.log("red changed" + mouseX)
    }
}

Rectangle {
    x: 130
    width: 30
    height: 30
    color: "green"
    MouseArea {
        hoverEnabled: true
        propagateComposedEvents: true

        anchors.fill: parent
        onMouseXChanged: console.log("green changed"+ mouseX)
    }
}

Everything works fine when i just move mouse between rectangles. But when i try to pres mouse button and then move - only one rectangle receive events. Is there a way to make it work with button pressed?

P.S. Initial problem, of course, is not with rectangles. Im trying to make combobox work quicker, when you need just one press to open popup and move cursor to item you want to select. But i can find a way to move press event from combobox input to popup. I think example i showed above is the right one to understand the problem.

1

1 Answers

1
votes

The problem is that once a button is pressed, the MouseArea holds the mouse events even if we move outside the area. Then the other MouseAreais not able to catch the mouse events.

The only solution I can imagine is to manage the change of position globally so that each MouseArea receives the positionChange signal from any other MouseArea and individually decides whether an action is needed or not (See mapFromItem for position mapping):

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

ApplicationWindow {
    visible: true
    width: 500
    height: 500

    signal globalPositionChanged(var item, var position)

    Rectangle {
        id: rect1
        x: 100
        width: 30
        height: 30
        color: "red"
        MouseArea {
            hoverEnabled: true
            propagateComposedEvents: true
            anchors.fill: parent
            clip: true

            onPositionChanged: {
                globalPositionChanged(rect1, mouse)
            }

            Component.onCompleted: {
                globalPositionChanged.connect(handlePositionChange)
            }

            function handlePositionChange(item, position) {
                var localPos = toLocalePosition(rect1, item, position)
                if (localPos) {
                    // we are in the red rectangle
                    console.log("red", localPos.x, localPos.y)
                }
            }
        }
    }

    Rectangle {
        id: rect2
        x: 130
        width: 30
        height: 30
        color: "green"
        MouseArea {
            hoverEnabled: true
            propagateComposedEvents: true
            clip: true
            anchors.fill: parent

            onPositionChanged: {
                globalPositionChanged(rect2, mouse)
            }

            Component.onCompleted: {
                globalPositionChanged.connect(handlePositionChange)
            }

            function handlePositionChange(item, position) {
                var localPos = toLocalePosition(rect2, item, position)
                if (localPos) {
                    // we are in the green rectangle
                    console.log("green", localPos.x, localPos.y)
                }
            }

        }
    }

    function toLocalePosition(toItem, fromItem, position) {
        // return the local position if inside item, or null if outside
        var localPos = toItem.mapFromItem(fromItem, position.x, position.y)
        if (localPos.x >= 0
                && localPos.y >= 0
                && localPos.x <= toItem.width
                && localPos.y <= toItem.height) {
            return localPos
        }
        return null
    }
}

I'm not 100% convinced about this answer. There are probably better ways to do it, but I think it fixes your problem.