PAYATHON 2026

重叠的 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 文档调整。

备注:内容仅供参考。