qml中,经常会遇到多个需要点击的组件重叠,点击重叠部分时,结果不符预期的问题。因为某个组件设置anchors.fill;parent,或者其他原因,不该触发的组件被触发,该触发的没反应。
作为qml的初学者,可能会很疑惑,调试半天,搞不明白哪里错了。也不知道在怎么设置,才能保证全部的需要点击的组件都可以正常运行。
我查了很多资料,只是谈mousearea用法,很少有人谈到这个问题。所以,我来简单说一下,避免更多新人像我一样踩坑。
预备知识
首先,了解什么叫做渲染。
已知一段qml代码,如下:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("渲染一个带有颜色的矩形")
Rectangle{
id:rectangle1
color: "lightblue"
anchors.fill: parent
}
}
运行代码,看到一个蓝色的矩形铺满整个窗口。
可知,渲染就是程序将代码指令变为屏幕上可显示图像的过程
我们已经渲染了一个ranctangle1,然后,再此基础上再渲染一个矩形rectangle2
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
}
}
运行程序,查看效果。
重点来了,仔细看
我要交换两个rectangle代码顺序,代码如下:
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
}
}
运行上述代码,查看效果。
很奇怪,两个重叠的rectangle,居然会因为定义的代码顺序不一样,渲染输出的结果不一样。
所以,问题的解决方法已经呼之欲出,关键就是代码顺序,mousearea或者qml其他组件是一样的道理。下面的内容可以不看。。。。
知识点:qml组件层级及其渲染顺序
qml的可视组件有xyz属性,xy决定组件的在屏幕的渲染位置
z轴垂直于屏幕,决定组件的渲染先后顺序,我称其为渲染层级
其值取值范围可以是正数负数,默认所有的组件z的值都是0,z值相同代表组件处同一个层级
不同层级间,将会按照z值,从小到大依次渲染
因此,手动设置z值,可以避免代码定义顺序的影响,调整组件在z轴上的位置
z值更小者处于更底层位置,z值最大者会处于渲染结果的最表面。
同一个层级下,遵循组件定义顺序为qml的渲染顺序,这一默认规则
此时,先定义的先被渲染,后被渲染的将处于窗口的表层
形象理解,渲染就像向桌子上贴贴纸,后来者会盖住前者。把所有贴纸贴到桌子上后,就是最终的渲染结果。最后贴的贴纸会处于桌面的表面,如果外层的贴纸大小大于内层贴纸,就会完全覆盖掉内层。就会导致看不到内层的贴纸图案。要想看到就得先撕下最外层。
解决方法
mousearea和button,还有许多qml组件,遵循以上运行规则。
因此,有多个重叠的可点击组件,想要正常被触发,就不能让大面积的组件完全叠在小面积组件上,否则点击小面积组件,响应的是大面积组件
所以解决方法很简单,就是调整渲染的先后顺序:
1.调整组件的定义顺序,先定义大面积组件,避免小面积组件后被覆盖掉
2.调整mousearea或button等多个组件的z值,让小面积组件裸露在重叠区域表层
两种方法根据情况和需求,选择使用即可
额外补充说明
这个方法,只能让点击位置最表面的那一个组件响应,内层不会响应
如果希望点击区域重叠的组件,被点击时都能响应。
就需要传递表层鼠标事件到内层,如果有多层重叠,需要一层一层传递鼠标事件才能保证全部响应
常用的设置方法我来简单介绍一下
把mousearea的属性propagateComposedEvents=true
并设置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;
}
}
}
}
原来未设置时,blue在最顶层,所以点击重叠部分只能输出clicked blue,
在blue中添加设置后,点击重叠区域,log就能输出 clicked blue,clicked yellow了
此时,如果将yellow设置z值设为1,blue的z值不变,点击重叠区域
则log又只能输出clicked yellow
这时向yellow添加设置,传递yellow的鼠标事件,log会再次输出两者: clicked yellow,clicked blue