QML MouseArea学习小结
QML中的MouseArea类型为用户进行简单的鼠标操作提供了方便。
MouseArea是一个不可见的Item,通常与可见项目结合使用,以便为该项目提供鼠标处理。通过有效地充当代理,鼠标处理的逻辑可以包含在MouseArea Item中。
MouseArea虽然是一个不可见的Item,但是它有一个“visible”属性,当该属性为假时,鼠标区域就对鼠标事件变得透明。
MouseArea使用实例:
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不能有效地获取实际形状的鼠标操作区域。如圆角矩形,在圆形按钮周围的假想方块的角落的鼠标操作也会被捕获,这显然不符合精准拾取的现实。
进阶地,文章“How to create a round mouse area in QML “提供了一种圆形鼠标区域RoundMouseArea:
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中使用:
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自带一个例子maskedmousearea,此示例提供了一种使用任何形状的Mask的方法,它可以根据您的需求进行定制。
先睹为快:
该demo是一个异形窗口,主要展示鼠标在和异形区域交互的使用,如上图所示,当鼠标移动到白云或者月亮上时,相应的物体会高亮,当鼠标按下时,物体会有一个放大的动画效果,鼠标离开时恢复原样。
class MaskedMouseArea : public QQuickItem
核心主要时判断鼠标点是否在图片有效区域内:
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; } |
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走起来: