qt - 如何将悬停或鼠标区域更新事件传播到 QML 中的较低元素?
问题描述
我有一些具有半径属性的兄弟 Rectangle 元素,因此它们显示为圆形。每个都有一个具有子 MouseArea 的子 Item,该 Item 的目的是实现“圆形鼠标区域”效果(原始 SO 答案)。对 Item 和 MouseArea 进行了检测,以便单击和拖动只会在 Rectangle 的可见圆形内生效,而不是在作为 Rectangle 实际足迹的边界框内生效。
不幸的是,下面显示了一个故障。拖动点时的预期结果是圆圈 1 移动,这在大多数情况下都会发生。但是,当您创建圆 1 然后圆 2 然后将鼠标光标移动到点时,它不会发生。如果您这样做并尝试拖动或单击,您的交互将落入后台全窗口 MouseArea 并创建一个新圆圈。
此问题的原因是当鼠标光标从圆圈#2 移动到点时,圆圈#1 的 MouseArea 的 mouseX 和 mouseY 没有得到更新。当圆 #2 允许点击向下传播时,它会击中圆 #1 的 Rectangle,但随后圆 #1 的 Item 声明 containsMouse 为 false 并再次向下传播。
一旦鼠标光标离开圆 #2 的边界矩形的足迹,例如从点向上或向左移动一点,圆 #1 的 MouseArea 就会更新,它的 containsMouse 变为 true,它开始再次捕获点击和拖动。
我已经尝试了一些潜在的解决方案,但并没有比下面的代码走得更远。
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
}
}
}
}
}
解决方案
这不是您问题的确切解决方案,但这就是我克服问题根源的方法。
在我的应用程序中,有一个MouseArea
与场景的大部分重叠的QQuickFrameBufferObject
. 这是我绘制 3D 场景的地方。由于您无法QHoverEvent
在 QML 中传播 a,因此您必须使用处理程序捕获位置更改信号onPositionChanged
并调用 C++ 中的方法,该方法将 a 发送QHoverEvent
到所需项目。
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);
}
};
推荐阅读
- reactjs - 在 axios POST 请求后更新状态而不是页面刷新
- java - 在 Java 中更改数组的值
- django - 无法使用 POST 请求值 Django 进行过滤
- javascript - 在单个端点上启用 CORS
- reactjs - 无法加载反应图像
- c++ - 声明对象的性能
- regex - 将 JSON-LD 中的数字值与正则表达式匹配
- wordpress - Wordpress — 用 TEXTAREA 替换 TinyMCE?
- operating-system - 用 ps/2 总线识别键盘
- android - Kotlin - 如何使用默认应用程序通过 Intent 打开 csv 文件?