QT-QML:解决多个qml组件重叠时表现异常的方法[以mousearea为例]

本文讲述了在QML中遇到的组件重叠点击问题,通过解析渲染顺序和组件层级,解释了如何调整代码顺序和Z值以确保正确触发。还介绍了如何使用`MouseArea`的`propagateComposedEvents`属性实现事件穿透。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

qml编程中,经常会遇到组件重叠的情况,结果响应异常

尤其有多个mousearea重叠的时候,希望点击时都响应,结果有一个死活不响应。作为qml的初学者,可能会很疑惑,调试半天,搞不明白哪里错了。。

我查了很多资料,都只是谈mousearea用法,很少有人清楚谈到这个问题。于是,我决定自己来讲,避免更多新人像我一样踩坑,无从解决。

 

基本原理

首先,需要理解qml组件渲染的基本规则。

渲染层级

先画两个大小矩形,如下:

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Rectangle{
        id:rectangle1
        color: "lightblue"
        anchors.fill: parent
    }

    Rectangle{
        id:rectangle2
        color: "pink"
        width: 100
        height: 100
    }
}

运行程序,查看效果。

然后交换代码顺序,先写粉色矩形的代码,如下

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Rectangle{
        id:rectangle2
        color: "pink"
        width: 100
        height: 100
    }

    Rectangle{
        id:rectangle1
        color: "lightblue"
        anchors.fill: parent
    }
}

结果如图,这时,粉色矩形被面积更大的蓝色矩形所覆盖。

为什么呢?只是交换了一下代码顺序,显示就不一样了呢?

qml组件显示到屏幕,就像把一层一层衣服摞起来。定义顺序会影响这个摞起来的顺序。

小的粉色矩形先定义,大的蓝色矩形后定义,导致大的蓝色矩形直接覆盖了小的粉色矩形。

这两个矩形换算成mousearea组件,大的mousearea覆盖掉了小的mousearea。这时点击小的mousearea区域,就只会触发大的mousearea.

 

 

因为渲染顺序错了,所以,重叠的时候才会响应异常。小的mousearea被大的覆盖,无法点击触发。

 

了解了组件层级的概念

怎么更改qml组件的层级顺序?

1.修改定义顺序

2.在可视组件中,还可修改z属性的值

可视组件继承于Item都会有xyz属性

z属性则是用来表示垂直于屏幕的一轴,决定各个组件所处的先后位置

其值取值范围可以是正数负数,z值相同代表组件处同一个层级,所有的组件z的值默认都是0

 

具体规则如下:

1.z值不同:z值更小者会处于更底层位置,z值更大者会处于渲染结果的表面,也就是用户看到的这一侧。

2.z值相同:由组件定义顺序决定组件的渲染顺序。先定义的先被渲染,后定义的后被渲染,最后定义的将处于结果的表层

 

多个mousearea重叠响应异常解决方法

到此,解决方法依然明了:

要么设定z值,保证要触发的组件在最高层级,或者调整定义顺序,来让它处于表面。

特别注意

这个方法主要用来避免大组件覆盖小组件

多个组件叠加,事件传递肯定是需要分先后的,不可能让所有组件同时处理事件,就是说在区域内点击,只有最表面的那个会响应点击事件

如果有特殊需求,让区域内重叠的多个mousearea 或 button都能响应点击事件

就需要一层一层地传递鼠标事件

设置方法如下

(别的博文更详细,我这里简单复述一下):

设置属性propagateComposedEvents=true

并在槽函数内接收鼠标事件对象mouse,设置mouse.accepted=false,表示当前鼠标事件没有被接收,可以继续向内传递到下一层,交给内层继续处理该类型鼠标事件

示例代码如下:
 

Rectangle {
    width: 100
    height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: console.log("clicked yellow")
    }

    Rectangle {
        color: "blue"
        width: 50
        height: 50

        MouseArea {
            anchors.fill: parent
            propagateComposedEvents: true
            onClicked: {
                console.log("clicked blue");
                mouse.accepted = false;
        }
      }
   }
}

 

 

更方便的鼠标事件处理方法 --- Handler

为了适应触屏设备,qt qml推出了一种更为简洁方便的鼠标键盘事件处理方法

最大的好处就是定义简洁方便,功能明确。彼此事件独立,能够避免像mousearea重叠时,事件传递异常,事件处理繁琐的问题。

这些组件作为子组件添加到父组件中,就可以让父组件具备对应的功能,示例如下:


ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Test handler conponent")

//pink rectangle    
    Rectangle{
        id:rectangle1
        width: 100
        height: 200
        color: "pink"
        TapHandler{
            onTapped: {
                console.log("rectangle1")
            }
        }
    }

//lightblue rectangle
    Rectangle{
        id:rectangle2
        anchors.fill: parent
        color:"lightblue"
        TapHandler{
            onTapped: {
                console.log("rectangle2")
            }
        }
    }
}

仍然以开头的例子举例,这里的蓝色矩形覆盖掉了粉色矩形,按照之前的介绍,

如果使用mousearea/button方法,不做任何处理,这里只能是rectangle2打印出log信息

但是使用handler组件,点击重叠区域,两个log信息都被打印,轻松解决问题

handler组件默认作用于父组件,也可以设置target来设定要作用的目标组件,结果只需编写一个响应事件的槽函数即可完成任务。

操作上更便捷

 

handler类型很多,当前qt6.7版本中,常见的handler组件如下:

    1.DragHandler{}   //处理拖拽事件,对所有基于item的组件有效
    2.TapHandler{}  //处理点击事件
    3.WheelHandler{}    //用于处理鼠标滚轮事件的组件。
    4.KeyEvent{}    //用于处理键盘事件的组件
    5.HoverHandler{}    // 用于处理鼠标悬停事件的组件

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值