重叠的 Qt Quick TableView 为什么会收到下层鼠标事件?
数据小陈
结论
上层 TableView 的空白处没有 delegate 接收点击,因此鼠标命中测试可能会落到下层可点击的 delegate 上。虽然 TableView 覆盖了可见区域,但并非每个位置都有 delegate 拦截鼠标。给 topScope 添加覆盖全区域的 MouseArea 可以接收空白处的点击,但也会挡住上层 delegate 的 MouseArea,导致 delegate 无法响应。
可以让覆盖层先判断点击位置是否落在上层的有效单元格内。若有单元格,通过 propagateComposedEvents 将点击继续传给 delegate;若点击在空白处,则由覆盖层接收并设置焦点。
处理方式
在上层 FocusScope 中添加覆盖层,并为上层 TableView 设置 id。下面的示例假设覆盖层与 topTable 对齐,因此点击坐标可以直接传给 indexAt():
FocusScope {
id: topScope
MouseArea {
anchors.fill: parent
z: 1
propagateComposedEvents: true
onClicked: function(mouse) {
const index = topTable.indexAt(mouse.x, mouse.y)
if (index.valid) {
mouse.accepted = false
} else {
topScope.forceActiveFocus()
}
}
}
TableView {
id: topTable
anchors.fill: parent
z: 2
// model、delegate 等原有设置
}
}
indexAt() 用于判断点击位置是否对应有效单元格。若单元格有效,将 mouse.accepted 设为 false,让合成点击事件继续传给下方 delegate 的 MouseArea;若没有单元格,则由覆盖层处理焦点。如果覆盖层和 TableView 的坐标原点或缩放不同,调用 indexAt() 前应先将鼠标坐标转换到 topTable 的坐标系。
注意事项
propagateComposedEvents 用于传播 clicked、doubleClicked 和 pressAndHold 等合成事件。此示例处理的是点击事件。若还需处理按下、拖动或滚动,应结合 Flickable 的手势与事件处理方式另行验证。indexAt() 的可用签名可能因 Qt 版本而异,请根据项目使用的 Qt 文档调整。
备注:内容仅供参考。
