2018年4月6日金曜日

MouseArea のマスク

Item の containmentMask にマスクオブジェクトを設定すると MouseArea のイベントをマスクできます。マスクオブジェクトとは以下を実装した QObject を継承したオブジェクトです。
Q_INVOKABLE QObject::contains(const QPoint& point)
QObject を継承したマスクオブジェクトは以下のようにして作成します。
main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QLineF>

class CircleMask : public QObject
{
    Q_OBJECT

    Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)

public:
    explicit CircleMask(QObject* parent = 0) : QObject(parent) {}

    ~CircleMask() {}

    qreal radius() const {
        return d.radius;
    }

    void setRadius(qreal radius)
    {
        if (d.radius == radius) {
            return;
        }
        d.radius = radius;
        emit radiusChanged();
    }

    Q_INVOKABLE bool contains(const QPointF& point) const
    {
        const QPointF center(d.radius, d.radius);
        const QLineF line(center, point);
        return line.length() <= d.radius;
    }

signals:
    void radiusChanged();

private:
    struct {
        qreal radius;
    } d;
};

int main(int argc, char** argv)
{
    QGuiApplication app(argc, argv);

    qmlRegisterType("Mask", 1, 0, "CircleMask");

    QQmlApplicationEngine engine;
    engine.load(QUrl("qrc:/main.qml"));

    return app.exec();
}

#include "main.moc"
contains() では point が半径 radius の円の内側かどうかを判定しています。
mail.qml:

import QtQuick 2.11
import QtQuick.Window 2.10
import Mask 1.0

Window {
    id: window

    visible: true

    minimumWidth: 300
    minimumHeight: 300

    color: "white"

    Rectangle {
        id: circle

        width: window.width/2; height: width
        anchors.centerIn: parent

        radius: width/2
        color: "red"
        border.width: circleMouseArea.containsMouse ? 4 : 0
        border.color: "firebrick"

        MouseArea {
            id: circleMouseArea

            anchors.fill: parent

            hoverEnabled: true
            containmentMask: CircleMask {
                radius: circle.radius
            }

            onPressed: {
                parent.color = "green";
            }

            onReleased: {
                parent.color = "red";
            }
        }
    }
}
MouseArea の containmentMask に半径を設定した CircleMask オブジェクトを設定すれば円の内側だけでマウスが反応するようになります。

円の内側だけでマウスが反応する

Qt Quick Shapes の Shape をオブジェクトマスクに使えます。containsMode を Shape.FillContains に設定すると内側だけに反応するようになります。
shapedmousearea.qml:

import QtQuick 2.11
import QtQuick.Shapes 1.11
import QtQuick.Window 2.10

Window {
    id: window

    visible: true

    minimumWidth: 300
    minimumHeight: 300

    color: "white"

    Shape {
        id: circle

        readonly property real radius: 60

        anchors.fill: parent

        layer.enabled: true
        layer.smooth: true
        layer.textureSize: Qt.size(2*width, 2*height)
        vendorExtensionsEnabled: false

        containsMode: Shape.FillContains

        ShapePath {
            id: halfArch

            strokeWidth: -1
            fillColor: "green"

            startX: circle.width/2 - circle.radius
            startY: circle.height/2 - circle.radius

            PathArc {
                id: halfPathArc

                x: circle.width/2 + circle.radius
                y: circle.height/2 + circle.radius
                radiusX: circle.radius
                radiusY: circle.radius
            }
        }
    }

    MouseArea {
        id: circleMouseArea

        anchors.fill: circle

        containmentMask: circle

        onPressed: {
            halfArch.fillColor = "red";
        }

        onReleased: {
            halfArch.fillColor = "green";
        }
    }
}
こちらも MouseArea の containmentMask に Shape オブジェクトをマスクとして設定します。こうすると半円の内側だけでマウスに反応します。Qt Quick Shapes を使えば不定形図形の描画とマスクに同じ Shape オブジェクトを使えます。

半円の内側だけでマウスに反応する


参考情報

containmentMask

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。