How to make double MouseArea take effect?

2019-07-08 08:47发布

问题:

Here is my QML code :

Rectangle
{
    .....
    Rectangle
    {
        ....height and width is smaller than parent
        MouseArea
        {
            id: mouseArea2
            anchors.fill: parent
            hoverEnabled: true

            onEntered:
            {
                console.log("enter 2")
            }
        }
    }


    MouseArea
    {
        id: mouseArea1
        anchors.fill: parent
        hoverEnabled: true

        onEntered:
        {
            console.log("enter 1")
        }
    }
}

Only mouseArea1 takes effect. If I remove mouseArea1 then mouseArea2 takes effect. So I think the mouse event must be handled by mouseArea1 and let it couldn't be passed to mouseArea2.

I search the document to find out which attr can prevent such behavior but nothing found. So how to let the mouseArea1 and mouseArea2 take effect at the same time?

回答1:

For "composed" mouse events -- clicked, doubleClicked and pressAndHold -- you can achieve this using the propagateComposedEvents property. But that won't work here because hover events are not composed events.

So what you need to do instead is to change the order in which the MouseAreas are evaluated.

One simple trick is to swap the order of the two MouseAreas in the QML source itself. By placing the smaller one after the larger one, the smaller one takes precedence:

Rectangle{
    //.....
    MouseArea{
        id: mouseArea1
        anchors.fill: parent
        hoverEnabled: true

        onEntered:{
            console.log("enter 1")
        }
    }

    Rectangle{
         //....height and width is smaller than parent
        MouseArea{
            id: mouseArea2
            anchors.fill: parent
            hoverEnabled: true

            onEntered:{
                console.log("enter 2")
            }
        }
    }
}

A second method that achieves the same thing is to add a z index to the topmost MouseArea that's greater than the lower one. By default every element has a z index of 0, so just adding z: 1 to the smaller MouseArea will do the trick:

Rectangle{
    //.....
    Rectangle{
        //....height and width is smaller than parent
        MouseArea{
            z: 1              // <-----------------
            id: mouseArea2
            anchors.fill: parent
            hoverEnabled: true

            onEntered:{
                console.log("enter 2")
            }
        }
    }

    MouseArea{
        id: mouseArea1
        anchors.fill: parent
        hoverEnabled: true

        onEntered:{
            console.log("enter 1")
        }
    }
}


回答2:

I have found the solution in the documentation. Take for instance the following QML code:

import QtQuick 2.0

Rectangle {
    color: "yellow"
    width: 100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: console.log("clicked yellow")
    }

    Rectangle {
        color: "blue"
        width: 50; height: 50

        MouseArea {
            anchors.fill: parent
            propagateComposedEvents: true
            onClicked: {
                console.log("clicked blue")
                mouse.accepted = false
            }
        }
    }
}

Here the yellow Rectangle contains a blue Rectangle. The latter is the top-most item in the hierarchy of the visual stacking order; it will visually rendered above the former.

Since the blue Rectangle sets propagateComposedEvents to true, and also sets MouseEvent::accepted to false for all received clicked events, any clicked events it receives are propagated to the MouseArea of the yellow rectangle beneath it.

Clicking on the blue Rectangle will cause the onClicked handler of its child MouseArea to be invoked; the event will then be propagated to the MouseArea of the yellow Rectangle, causing its own onClicked handler to be invoked.