QML MouseArea学习小结

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不能有效地获取实际形状的鼠标操作区域。如圆角矩形,在圆形按钮周围的假想方块的角落的鼠标操作也会被捕获,这显然不符合精准拾取的现实。

进阶地,文章“How to create a round mouse area in QML “提供了一种圆形鼠标区域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) / 22);
        
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自带一个例子maskedmousearea,此示例提供了一种使用任何形状的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 * 255255);
    
//根据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走起来:

posted on 2019-07-24 15:58  我来乔23  阅读(1580)  评论(0编辑  收藏  举报

导航