QML中的MouseArea类型为用户进行简单的鼠标操作提供了方便。
MouseArea是一个不可见的Item,通常与可见项目结合使用,以便为该项目提供鼠标处理。通过有效地充当代理,鼠标处理的逻辑可以包含在MouseArea Item中。
MouseArea虽然是一个不可见的Item,但是它有一个“visible”属性,当该属性为假时,鼠标区域就对鼠标事件变得透明。
MouseArea使用实例:
main.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | import QtQuick 2 . 12 import QtQuick.Window 2 . 12 Window { id : window visible : true width : 640 height : 480 title : qsTr( "Mouse Area" ) Rectangle { id : rect anchors.left : window.left anchors.leftMargin : 10 width : 100 ; height : 100 color : "green" MouseArea { anchors.fill : parent onClicked : { parent.color = 'red' ; } } } Rectangle { id : roundrect anchors.left : rect.right anchors.leftMargin : 10 width : 100 ; height : 100 color : "red" radius : 20 MouseArea { anchors.fill : parent onClicked : { parent.color = 'green' } } } } |
常规测试实验证实,MouseArea有一个矩形的形状区域,这就会导致一些不是矩形形状的Item不能有效地获取实际形状的鼠标操作区域。如圆角矩形,在圆形按钮周围的假想方块的角落的鼠标操作也会被捕获,这显然不符合精准拾取的现实。
进阶地,文章““提供了一种圆形鼠标区域RoundMouseArea:
RoundMouseArea.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import QtQuick 2 . 0 Item { id: roundMouseArea property alias mouseX: mouseArea.mouseX property alias mouseY: mouseArea.mouseY property bool containsMouse: { var x1 = width / 2 ; var y1 = height / 2 ; var x2 = mouseX; var y2 = mouseY; var distanceFromCenter = Math.pow(x1 - x2, 2 ) + Math.pow(y1 - y2, 2 ); var radiusSquared = Math.pow(Math.min(width, height) / 2 , 2 ); var isWithinOurRadius = distanceFromCenter < radiusSquared; return isWithinOurRadius; } readonly property bool pressed: containsMouse && mouseArea.pressed signal clicked MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: if (roundMouseArea.containsMouse) roundMouseArea.clicked() } } |
main.qml中使用:
main.qml片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | RoundMouseArea { id : roundMouseArea width : 100 height : 100 anchors.centerIn : parent onClicked : print( "clicked" ) // Show the boundary of the area and whether or not it's hovered. Rectangle { color : roundMouseArea.pressed ? "red" : (roundMouseArea.containsMouse ? "darkorange" : "transparent" ) border.color : "darkorange" radius : width / 2 anchors.fill : parent } } |
我们可以根据需要重写containsMouse来规定自己的鼠标区域,但是需要计算不同区域的数学知识,需要一定的功底。
再进一步,应该把鼠标区域一般化,可以使用任意的路径形状来表示才好。Qt自带一个例子,此示例提供了一种使用任何形状的Mask的方法,它可以根据您的需求进行定制。
先睹为快:
该demo是一个异形窗口,主要展示鼠标在和异形区域交互的使用,如上图所示,当鼠标移动到白云或者月亮上时,相应的物体会高亮,当鼠标按下时,物体会有一个放大的动画效果,鼠标离开时恢复原样。
class MaskedMouseArea : public QQuickItem
核心主要时判断鼠标点是否在图片有效区域内:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | bool MaskedMouseArea::contains( const QPointF &point) const { if (!QQuickItem::contains(point) || m_maskImage.isNull()) return false ; QPoint p = point.toPoint(); if (p.x() < 0 || p.x() >= m_maskImage.width() || p.y() < 0 || p.y() >= m_maskImage.height()) return false ; qreal r = qBound< int >( 0 , m_alphaThreshold * 255 , 255 ); //根据alpha值判断 异形区域 return qAlpha(m_maskImage.pixel(p)) > r; } |
qml Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | Image { id : moon anchors.centerIn : parent scale : moonArea.pressed ? 1 . 1 : 1 . 0 opacity : moonArea.containsMouse ? 1 . 0 : 0 . 7 source : Qt.resolvedUrl( "images/moon.png" ) MaskedMouseArea { id : moonArea anchors.fill : parent alphaThreshold : 0 . 4 maskSource : moon.source } Behavior on opacity { NumberAnimation { duration : 200 } } Behavior on scale { NumberAnimation { duration : 100 } } } |
gif走起来: