如何将悬停或mousearea更新事件传播到QML中的较低元素? [英] How can I propagate hover or mousearea update events to lower elements in QML?

查看:421
本文介绍了如何将悬停或mousearea更新事件传播到QML中的较低元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些具有radius属性的同级Rectangle元素,因此它们显示为圆形.每个子项都有一个子项,该子项具有一个子MouseArea,该项的目的是实现圆形鼠标区域"效果(

I have some sibling Rectangle elements with a radius property so they appear as circles. Each has a child Item that has a child MouseArea, the purpose of the Item being to implement a "round mouse area" effect (original SO answer). The Item and MouseArea are instrumented such that clicks and drags will only take effect within the visible circular shape of the Rectangle, not within the bounding box that is the real footprint of the Rectangle.

不幸的是,下面显示了一个小故障.在圆点处拖动时,期望的结果是使圆1移动,并且在大多数情况下会发生这种情况.但是,当您创建创建圆圈1然后圆圈2然后将鼠标光标移动到该点时,不会发生这种情况.如果这样做并尝试拖动或单击,则您的交互将落入背景全窗口MouseArea并创建一个新的圆圈.

Unfortunately there is a glitch illustrated below. The desired outcome when dragging at the dot is for circle 1 to move, and this happens in most circumstances. However, it does not happen when you create create circle 1 then circle 2 then move your mouse cursor to the dot. If you do that and attempt to drag or click, your interaction will fall through to the background full-window MouseArea and create a new circle.

此问题的原因是,当鼠标光标从圆#2移到点时,圆1的MouseArea的mouseX和mouseY不会更新.当第2圈允许点击向下传播时,它会碰到第1圈的矩形,但随后第1圈的Item声明containsMouse为false并再次向下传播.

The cause of this problem is that when the mouse cursor moves to the dot from circle #2, the mouseX and mouseY for circle #1's MouseArea do not get updated. When circle #2 allows the click to propagate downward, it hits the Rectangle of circle #1 but then circle #1's Item claims containsMouse is false and it propagates downward again.

一旦鼠标光标离开圆2的边界矩形的足迹,例如通过从点向上或向左移动一点,圆1的MouseArea就会更新,并且其containsMouse变为true,并开始捕获点击和拖动再次.

As soon as the mouse cursor leaves the footprint of circle #2's bounding rectangle, such as by moving a bit up or left from the dot, circle #1's MouseArea gets updated and its containsMouse becomes true and it starts capturing clicks and drags again.

我已经尝试了一些潜在的解决方案,并且没有比下面的代码做得更多.

I have tried a handful of potential solutions and not gotten much farther than the code below.

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
                }
            }
        }
    }
}

推荐答案

这不是解决您问题的确切方法,但这是我克服问题根源的方法.

This is not the exact solution for your problem, but this is how I overcame the root of the issue.

在我的应用程序中,有一个MouseArea与场景的很大一部分(QQuickFrameBufferObject)重叠.这是我绘制3D场景的地方.由于无法在QML中传播QHoverEvent,因此必须使用onPositionChanged处理程序捕获位置已更改信号,并调用C ++中的方法,该方法会将QHoverEvent发送到所需项目

In my application there is a MouseArea that overlaps a large chunk of the scene which is a QQuickFrameBufferObject. This is where I draw the 3D scene. Since you cannot propagate a QHoverEvent in QML, you will have to catch the position changed signal using the onPositionChanged handler and invoke a method in C++ which will send a QHoverEvent to the required items.

QML:

MouseArea {
    onPositionChanged: {
        model.sendHoverEvent(Qt.point(mouse.x, mouse.y))
    }
}

C ++:

class TreeViewModel : public QAbstractListModel
{
    // ...
    void TreeViewModel::sendHoverEvent(QPointF p) {
        QHoverEvent hoverEvent(QEvent::HoverMove, p, p);
        QApplication::sendEvent(mApplication.graphicsLayer(), &hoverEvent);
    }
};

这篇关于如何将悬停或mousearea更新事件传播到QML中的较低元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆