解决Qml中的Rectangle圆角外部区域也会触发鼠标事件的问题
背景 🔔
在很多场景下,有用到各种带有圆角属性的
Rectangle
作为交互的控件,当radius
设置的比较大时,鼠标悬浮在外部区域也会触发各种信号。比较头疼。
比如,以下代码通过Rectangle实现了一个圆形控件。然后创建一个MouseArea,当鼠标进入圆形区域,希望看到圆的颜色会发生改变。
Item {
id: root
anchors.centerIn: parent
width: 200
height: 200
property real cornerRadius: 100
Rectangle {
anchors.fill: parent
radius: root.cornerRadius
color: mouseArea.containsMouse ? "lightblue" : "blue"
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
}
}
}
然而实际效果却是还没进行圆形区域就触发了信号,Rectangle虽然设置了radius,圆角外部还是属于Rectangle的范围,所以会触发。
解决方案 🔔
Item {
id: root
anchors.centerIn: parent
width: 200
height: 200
property real cornerRadius: Math.min(width/2, height/2)
readonly property alias containsMouse: mouseArea.isOk
Rectangle {
anchors.fill: parent
radius: root.cornerRadius
color: mouseArea.isOk ? "lightblue" : "blue"
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
property bool isOk: false
onContainsMouseChanged: {
isOk = containsMouse ? isPointInRoundedRect(mouseX, mouseY, 0, 0, width, height, root.cornerRadius) : false
}
onPositionChanged: function(mouse) {
isOk = root.isPointInRoundedRect(mouse.x, mouse.y, 0, 0, width, height, root.cornerRadius);
}
// 判断点是否在圆角矩形内的函数
function isPointInRoundedRect(x, y, rx, ry, rw, rh, r) {
if (x < rx || x > rx + rw || y < ry || y > ry + rh)
return false;
var dx = Math.abs(x - rx - rw/2);
var dy = Math.abs(y - ry - rh/2);
if (dx > rw/2 - r && dy > rh/2 - r) {
var dx2 = dx - rw/2 + r;
var dy2 = dy - rh/2 + r;
return (dx2*dx2 + dy2*dy2 <= r*r);
}
return true;
}
}
}
}