Как я могу распространять события обновления при наведении курсора или области мыши на нижние элементы в QML? - PullRequest
0 голосов
/ 18 декабря 2018

У меня есть несколько родственных элементов Rectangle со свойством radius, поэтому они отображаются в виде кругов.Каждый из них имеет дочерний элемент, имеющий дочернюю мышь MouseArea, цель элемента заключается в реализации эффекта «круглой области мыши» ( оригинальный ответ SO ).Item и MouseArea оснащены такими инструментами, что щелчки и перетаскивания будут действовать только в пределах видимой круглой формы прямоугольника, а не в пределах ограничивающей рамки, которая является реальной площадью прямоугольника.ниже.При перетаскивании по точке желаемый результат - движение круга 1, и это происходит в большинстве случаев.Однако этого не происходит, когда вы создаете круг 1, затем круг 2, а затем перемещаете курсор мыши на точку.Если вы сделаете это и попытаетесь перетащить или щелкнуть, ваше взаимодействие переместится в фоновое полноэкранное MouseArea и создаст новый круг.

two circles partially overlapping, numbered 1 and 2, with a dot in one circle near the other

Причиной этой проблемы является то, что когда курсор мыши перемещается к точке из круга # 2, mouseArea и mouseY для круга # 1 MouseArea не обновляются.Когда круг № 2 позволяет щелчку распространяться вниз, он попадает в прямоугольник круга № 1, но затем элемент № 1 круга утверждает, что содержит значение «false» и снова распространяется вниз.

Как только курсор мыши покидает следограничивающего прямоугольника круга # 2, например, немного переместившись вверх или влево от точки, MouseArea круга # 1 обновляется, и его containsMouse становится истинным, и он начинает захватывать щелчки и перетаскивать.

Я пробовалГорстка потенциальных решений и не намного дальше, чем приведенный ниже код.

import QtQuick 2.12
import QtQuick.Controls 2.5

ApplicationWindow {
    visible: true
    width: 640
    height: 480

    property real spotlightRadius: 100

    MouseArea {
        visible: true
        anchors.fill: parent
        onClicked: {
            spotlightComponent.createObject(parent, {
                "x": x + mouseX - spotlightRadius,
                "y": y + mouseY - spotlightRadius,
                "width": spotlightRadius * 2,
                "height": spotlightRadius * 2
            })
        }
    }

    Component {
        id: spotlightComponent
        Rectangle {
            id: spotlightCircle
            visible: true
            x: parent.x
            y: parent.y
            width: parent.width
            height: parent.height
            radius: Math.max(parent.width, parent.height) / 2
            color: Qt.rgba(Math.random()*0.5+0.5,Math.random()*0.5+0.5,Math.random()*0.5+0.5,0.5);
            Item {
                anchors.fill: parent
                drag.target: parent
                onDoubleclicked: parent.destroy()
                onWheel: { parent.z += wheel.pixelDelta.y; currentSpotlight = parent }

                property alias drag: mouseArea.drag

                //FIXME when moving the mouse out of a higher element's containsMouse circle
                // but still inside its mouseArea.containsMouse square, lower elements'
                // mouseArea do not update, so their containsMouse doesn't update, so clicks
                // fall through when they should not.
                property bool containsMouse: {
                    var x1 = width / 2;
                    var y1 = height / 2;
                    var x2 = mouseArea.mouseX;
                    var y2 = mouseArea.mouseY;
                    var deltax = x1 - x2;
                    var deltay = y1 - y2;
                    var distance2 = deltax * deltax + deltay * deltay;
                    var radius2 = Math.pow(Math.min(width, height) / 2, 2);
                    return distance2 < radius2;
                }

                signal clicked(var mouse)
                signal doubleclicked(var mouse)
                signal wheel(var wheel)

                MouseArea {
                    id: mouseArea
                    anchors.fill: parent
                    hoverEnabled: true
                    //FIXME without acceptedButtons, propagated un-accepted clicks end up with the wrong coordinates
                    acceptedButtons: parent.containsMouse ? Qt.LeftButton : Qt.NoButton
                    propagateComposedEvents: true
                    onClicked: { if (parent.containsMouse) { parent.clicked(mouse) } else { mouse.accepted = false } }
                    onDoubleClicked: { if (parent.containsMouse) { parent.doubleclicked(mouse) } }
                    onWheel: { if (parent.containsMouse) { parent.wheel(wheel) } }
                    drag.filterChildren: true
                }
            }
        }
    }
}

1 Ответ

0 голосов
/ 18 декабря 2018

Вам необходимо отклонить событие pressed вашего базового MouseArea.Этого должно быть достаточно, чтобы решить ваши проблемы.Если нажатое событие отклонено, щелчок будет автоматически переадресован нижележащим элементам одного уровня.propagateComposedEvents и filterChildren в вашем случае бесполезны.

Обратите внимание, что если событие колеса приводит к тому, что координата z вашего spotlightCircle становится меньше 0, оно больше не будет принимать событие мыши, так как они будут перехвачены"Творением" MouseArea

import QtQuick 2.10
import QtQuick.Controls 2.3

ApplicationWindow {
    visible: true
    width: 640
    height: 480

    property real spotlightRadius: 100

    MouseArea {
        visible: true
        anchors.fill: parent
        onClicked: {
            spotlightComponent.createObject(parent, {
                "x": x + mouseX - spotlightRadius,
                "y": y + mouseY - spotlightRadius,
                "width": spotlightRadius * 2,
                "height": spotlightRadius * 2
            })
        }
    }

    Component {
        id: spotlightComponent
        Rectangle {
            id: spotlightCircle
            visible: true
            x: parent.x
            y: parent.y
            width: parent.width
            height: parent.height
            radius: Math.max(parent.width, parent.height) / 2
            color: Qt.rgba(Math.random()*0.5+0.5,Math.random()*0.5+0.5,Math.random()*0.5+0.5,0.5);
            Item {
                anchors.fill: parent
                onDoubleClicked: parent.destroy()
                onWheel: { parent.z += wheel.pixelDelta.y; currentSpotlight = parent }

                signal clicked(var mouse)
                signal pressed(var mouse)
                signal doubleClicked(var mouse)
                signal wheel(var wheel)
                property alias drag: mouseArea.drag
                property bool containsMouse: {
                    var x1 = width / 2;
                    var y1 = height / 2;
                    var x2 = mouseArea.mouseX;
                    var y2 = mouseArea.mouseY;
                    var deltax = x1 - x2;
                    var deltay = y1 - y2;
                    var distance2 = deltax * deltax + deltay * deltay;
                    var radius2 = Math.pow(Math.min(width, height) / 2, 2);
                    return distance2 < radius2;
                }

                MouseArea {
                    id: mouseArea
                    anchors.fill: parent
                    hoverEnabled: true
                    drag.target: spotlightCircle
                    onPressed: { if (parent.containsMouse) { parent.pressed(mouse) } else { mouse.accepted = false } }
                    onClicked: { if (parent.containsMouse) { parent.clicked(mouse) } else { mouse.accepted = false } }
                    onDoubleClicked: { if (containsMouse2) { parent.doubleClicked(mouse) } }
                    onWheel: { if (parent.containsMouse) { parent.wheel(wheel) } }
                }
            }

        }
    }
}
...