【Qt QML】Item.containmentMaskのよくあるエラーと解決策

2025-06-06

Item.containmentMask とは?

Item.containmentMaskは、QMLのItem型に存在するプロパティで、主にポインタイベント(マウスやタッチイベントなど)がそのアイテムに「着地した」と判断される領域を、アイテムの境界ボックス(bounding box)以外の形状で定義するために使用されます。

通常、QMLのアイテムは、そのwidthheightで定義される四角い境界ボックス内にポインタがある場合に「イベントが着地した」と判断します。しかし、containmentMaskを使用すると、この判断ロジックをより細かく制御し、非長方形の領域(例えば、円形やカスタムシェイプなど)でもイベントを処理できるようになります。

どのように機能するか?

containmentMaskには、contains()という関数を持つ別のItemまたはQtObjectを設定します。設定されたcontainmentMaskオブジェクトのcontains()メソッドがtrueを返す場合にのみ、元のアイテムのcontains()メソッドもtrueを返します。つまり、ポインタイベントのヒットテストにおいて、マスクとして機能するアイテムのcontains()ロジックが適用されるわけです。

別のItemをマスクとして使用する

あるアイテム(item)のイベント領域を、別のアイテム(anotherItem)の形状に合わせたい場合:

Item {
    id: item
    width: 200
    height: 200
    color: "lightblue" // 例として色をつけます
    TapHandler {
        onTapped: console.log("Item tapped!")
    }

    containmentMask: AnotherItem { // ここにマスクとなるアイテムを指定
        id: anotherItem
        width: 100
        height: 100
        x: 50
        y: 50
        // AnotherItem が独自の contains() ロジックを持つか、
        // 単純にその境界ボックスを使用します。
    }
}

この場合、itemへのタップは、anotherItemの領域内で発生した場合にのみ検出されます。

Shapeをマスクとして使用する(非長方形のヒットテスト)

Shapeエレメントを使用して、非長方形の領域をマスクとして定義することができます。これにより、円形や星形など、複雑な形状に対するポインタイベントの反応を実現できます。

Rectangle {
    width: 200
    height: 200
    color: hoverHandler.hovered ? "wheat" : "lightgray" // ホバー時に色が変わる
    TapHandler {
        onTapped: console.log("Rectangle tapped!")
    }
    HoverHandler {
        id: hoverHandler
    }

    containmentMask: Shape { // Shapeをマスクとして使用
        id: shape
        containsMode: Shape.FillContains // 塗りつぶされた領域をヒットテスト対象とする

        ShapePath {
            fillColor: "lightsteelblue"
            startX: 100; startY: 10 // 上の頂点
            PathLine { x: 10; y: 150 } // 左下の頂点
            PathLine { x: 190; y: 150 } // 右下の頂点
            PathLine { x: 100; y: 10 } // 上の頂点に戻る
        }
    }
}

この例では、長方形のアイテムですが、その内部のShape(三角形)の領域にマウスがホバーしたりタップされたりした場合にのみイベントが発火します。

QML内でcontains()メソッドを定義する

QtObjectを利用して、完全にカスタムなcontains()ロジックをQML内で直接定義することも可能です。これにより、例えば円形のアイテムがその実際の円形領域でのみイベントに応答するように設定できます。

Rectangle {
    id: circle
    width: 100
    height: width // 正方形にして円形にする
    radius: width / 2 // 角丸を半径の半分にすることで円形に
    color: tapHandler.pressed ? "tomato" : hoverHandler.hovered ? "darkgray" : "lightgray"

    TapHandler {
        id: tapHandler
    }
    HoverHandler {
        id: hoverHandler
    }

    containmentMask: QtObject {
        property alias radius: circle.radius // 親の円の半径を参照

        function contains(point) : bool {
            // 中心からの距離が半径以内かどうかをチェック
            // point.x, point.y はアイテムローカル座標
            var centerX = radius;
            var centerY = radius;
            return (Math.pow(point.x - centerX, 2) + Math.pow(point.y - centerY, 2)) < Math.pow(radius, 2);
        }
    }
}

この例では、Rectangleは見た目は円形ですが、デフォルトのcontains()メソッドは四角い境界ボックスでヒットテストを行います。containmentMaskでカスタムのQtObjectとそのcontains関数を定義することで、実際に円の形状でヒットテストを行うようになります。



Item.containmentMaskは、ポインタイベントのヒットテスト領域を定義するために使われるため、主にイベントが期待通りに発生しないという問題に直面することが多いです。

contains() メソッドが実装されていない、または正しくない

エラーの症状
アイテムがまったくイベントに応答しない、または予期せぬ領域でイベントに応答する。コンソールに「Object set as mask does not have an invokable contains method, ignoring it.」のような警告が表示されることがあります。

原因
containmentMaskに設定されたオブジェクト(QtObjectや別のItemなど)に、QMLエンジンが呼び出し可能なcontains(point: point)関数が定義されていない、またはそのシグネチャ(引数の型や戻り値の型)が正しくない場合。pointQPointFに対応するQMLのpoint型である必要があります。

トラブルシューティング

  • Shapeを使用する場合のcontainsMode
    ShapecontainmentMaskとして使用する場合、containsModeプロパティを適切に設定しているか確認してください。通常はShape.FillContainsを使用します。
    containmentMask: Shape {
        containsMode: Shape.FillContains // これが重要
        // ... ShapePath ...
    }
    
  • シグネチャの確認
    引数がpoint型(Qt.pointではないことに注意)で、戻り値がbool型であることを確認してください。
    // 正しい例
    containmentMask: QtObject {
        function contains(p) : bool { // 'p' は任意の引数名
            // ... ロジック ...
            return true;
        }
    }
    
    // 間違いやすい例 (型指定の誤り)
    // containmentMask: QtObject {
    //     function contains(p: Qt.point) : bool { ... } // 'Qt.point' ではなく 'point'
    // }
    
  • contains関数の存在確認
    containmentMaskに設定するオブジェクト内にfunction contains(point) : bool { ... }の形式で関数が定義されているか確認してください。

マスクアイテムの座標系とサイズ

エラーの症状
イベントが検出される領域が、視覚的なマスクの形状とずれている。

原因
containmentMaskに設定されたアイテム(またはQtObject内のcontainsロジック)が、親アイテムのローカル座標系を正しく考慮していない場合。contains()関数に渡されるpointは、マスクを設定された元のアイテムのローカル座標で提供されます。したがって、containmentMaskとして設定されたアイテムのx, y, width, heightなどが、元のアイテムの座標系に対してどのように配置されているかを理解する必要があります。

トラブルシューティング

  • デバッグ用可視化
    デバッグのために、containmentMaskとして使用しているアイテムを一時的に可視化(例: colorプロパティを設定する、visible: trueにする)して、その配置とサイズが期待通りか確認すると良いでしょう。
  • マスクアイテムの配置
    • containmentMaskとして別のItemを使用する場合、そのItemx, y, width, heightが、元のアイテムの領域に対して適切に配置されているか確認します。通常、元のアイテムの左上隅を基準(0,0)として考えます。
    • カスタムcontains()関数を記述する場合、point.xpoint.yが、マスクを設定された元のアイテムの左上隅からのオフセットであることを意識して計算ロジックを記述します。

複数のポインタハンドラーとの競合

エラーの症状
containmentMaskを設定したにも関わらず、イベントが期待通りに処理されない、または他のアイテムがイベントを横取りしてしまう。

原因
一つのアイテムに複数のポインタハンドラー(TapHandler, MouseArea, HoverHandlerなど)が存在する場合、または子アイテムや親アイテムがイベントを処理している場合、イベントの伝播と処理の優先順位が複雑になることがあります。containmentMaskItem自身のcontains()メソッドの動作を変更するものであり、他のポインタハンドラーの動作ロジックに直接影響を与えるわけではありません。

トラブルシューティング

  • イベントフローの理解
    QMLのイベント処理の仕組み(イベント伝播、ハンドラーの優先順位など)を理解することが重要です。一般的には、子から親へイベントが伝播し、ハンドラーは自身のcontains()メソッドがtrueを返した場合にイベントを処理します。
  • enabledプロパティ
    必要に応じて、ポインタハンドラーやアイテムのenabledプロパティを制御し、不要なハンドラーを無効にします。
  • acceptedプロパティ
    ポインタハンドラーのacceptedプロパティ(例: TapHandler { accepted: true })を適切に設定し、イベントがそこで消費されるようにするか、またはイベントがさらに伝播するようにするかを制御します。

パフォーマンスへの影響

エラーの症状
containmentMaskを使用したUIの動作が重い、フレームレートが低下する。

原因
特に複雑なShapecontainmentMaskとして使用したり、contains()関数内で複雑な計算を行ったりすると、ポインタイベントが発生するたびにその計算が実行されるため、パフォーマンスに影響を与える可能性があります。

トラブルシューティング

  • 必要な場合のみ使用
    本当に非長方形のヒットテストが必要な場合にのみcontainmentMaskを使用し、そうでない場合は通常のMouseAreaTapHandlerwidth, heightを利用します。
  • Shapeの最適化
    Shapeを使用する場合、ShapePathの頂点数を減らすなど、形状を簡素化することを検討します。
  • 複雑な計算の回避
    contains()関数内で、できるだけシンプルで高速な計算を使用するように心がけます。

QMLのキャッシュとリロードの問題

エラーの症状
コードを変更してもcontainmentMaskの動作が変わらない、または予期せぬ動作をする。

原因
QMLのキャッシュや、アプリケーションのリロード(特に開発中)の際に、古い状態が残ってしまうことがあります。

  • アプリケーションの再起動
    アプリケーションを完全に終了し、再起動してみます。
  • QMLエンジンキャッシュのクリア
    デプロイ環境によっては、QMLエンジンのキャッシュを手動でクリアする必要がある場合があります。
  • クリーンビルド
    プロジェクトをクリーンして再ビルドしてみてください。


基本的な使用法: 別の Item をマスクとして使用する

最も基本的な例として、ある Rectangle のタップ検出領域を、その内部にある別の Rectangle の領域に制限するケースです。

// main.qml
import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: "Containment Mask Basic Example"

    // メインの長方形(見かけは大きいが、タップ領域は小さい)
    Rectangle {
        id: outerRectangle
        width: 300
        height: 300
        color: "lightblue"
        anchors.centerIn: parent

        // この TapHandler は containmentMask の領域内でしか発火しない
        TapHandler {
            onTapped: console.log("Outer Rectangle tapped within mask area!")
        }

        // containmentMask として別の Item を指定
        // この innerRectangle の領域のみが outerRectangle のタップ可能領域となる
        containmentMask: Rectangle {
            id: innerRectangle
            width: 100
            height: 100
            color: "lightcoral" // デバッグ用に可視化
            anchors.centerIn: parent
            // innerRectangle 自体はイベントハンドラーを持たない
        }
    }
}

解説
outerRectangle300x300 の大きさですが、その containmentMask に設定された innerRectangle100x100 です。この結果、outerRectangle をタップしても、innerRectangle100x100 の領域内でのみ onTapped シグナルが発火します。innerRectanglecontainmentMask の役割を果たすため、通常は visible: falseopacity: 0 に設定して非表示にすることが多いです。

Shape を使用して非長方形のマスクを作成する(円形ボタン)

Shape QMLタイプは、パスに基づいて複雑な形状を描画できます。これをcontainmentMaskとして使用することで、円形や多角形のような非長方形のイベント領域を作成できます。

// main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Shapes 1.15 // Shape を使うためにインポート

Window {
    width: 640
    height: 480
    visible: true
    title: "Containment Mask with Shape"

    // 見た目は四角いボタン(実際には円形に反応)
    Rectangle {
        id: circleButton
        width: 150
        height: 150
        color: "lightgreen"
        radius: width / 2 // 見た目を円形にするため
        anchors.centerIn: parent

        TapHandler {
            onTapped: console.log("Circle button tapped!")
        }
        HoverHandler {
            onHoveredChanged: circleButton.color = hoverHandler.hovered ? "gold" : "lightgreen"
        }

        // containmentMask として Shape を使用
        containmentMask: Shape {
            // containsMode: Shape.FillContains が重要。
            // これにより、Shape の「塗りつぶされた領域」がヒットテストの対象となる。
            containsMode: Shape.FillContains
            antialiasing: true // アンチエイリアスを有効にするとより滑らか
            width: circleButton.width
            height: circleButton.height

            ShapePath {
                fillColor: "transparent" // マスクなので透明でOK
                strokeWidth: 0 // 線も不要
                // 円を描画
                PathArc {
                    x: width / 2
                    y: height / 2
                    radiusX: width / 2
                    radiusY: height / 2
                    startAngle: 0
                    endAngle: 360
                }
            }
        }
    }
}

解説
circleButtonRectangle なので、デフォルトでは四角い領域でイベントを検出します。しかし、containmentMask に円形のShapeを設定し、containsMode: Shape.FillContains とすることで、実際の円の領域内でのみタップやホバーイベントが検出されるようになります。これにより、見た目の形状とインタラクションの領域が一致します。

カスタムの contains() メソッドを QtObject で定義する

より複雑なロジックや、特定の計算に基づいてイベント領域を定義したい場合は、QtObject を使用して独自の contains() 関数を実装できます。

// main.qml
import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: "Containment Mask with Custom Contains Method"

    // 星形を模したイベント領域を持つアイテム
    Rectangle {
        id: starItem
        width: 200
        height: 200
        color: "lightsalmon"
        anchors.centerIn: parent

        // デバッグ用に、タップ時に色を変える
        TapHandler {
            onTapped: {
                console.log("Star item tapped!");
                starItem.color = "red";
                // 短時間後に元の色に戻す
                Qt.callLater(function() { starItem.color = "lightsalmon"; });
            }
        }

        // containmentMask に QtObject を設定し、カスタムの contains() メソッドを定義
        containmentMask: QtObject {
            // 星の頂点座標(starItem のローカル座標系)
            // 例として、単純な五芒星の頂点を定義
            property var starPoints: [
                Qt.point(100, 10),    // Top
                Qt.point(125, 75),    // Right-top inner
                Qt.point(190, 80),    // Right outer
                Qt.point(140, 130),   // Right-bottom inner
                Qt.point(160, 190),   // Right-bottom outer
                Qt.point(100, 150),   // Bottom
                Qt.point(40, 190),    // Left-bottom outer
                Qt.point(60, 130),    // Left-bottom inner
                Qt.point(10, 80),     // Left outer
                Qt.point(75, 75)      // Left-top inner
            ]

            // pointInPolygon 関数(レイトレーシングアルゴリズム)
            // point: テストする点 (アイテムローカル座標)
            // polygon: 多角形の頂点リスト (Qt.point の配列)
            function contains(point) : bool {
                var x = point.x, y = point.y;
                var inside = false;
                for (var i = 0, j = starPoints.length - 1; i < starPoints.length; j = i++) {
                    var xi = starPoints[i].x, yi = starPoints[i].y;
                    var xj = starPoints[j].x, yj = starPoints[j].y;

                    var intersect = ((yi > y) != (yj > y))
                        && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
                    if (intersect) inside = !inside;
                }
                return inside;
            }
        }

        // 星形の視覚的な表示 (オプション: デバッグ用)
        Shape {
            anchors.fill: parent
            antialiasing: true
            z: -1 // 背景として描画

            ShapePath {
                fillColor: "transparent"
                strokeColor: "darkblue"
                strokeWidth: 2
                startX: starItem.containmentMask.starPoints[0].x
                startY: starItem.containmentMask.starPoints[0].y

                Repeater {
                    model: starItem.containmentMask.starPoints.length - 1
                    PathLine {
                        x: starItem.containmentMask.starPoints[modelData + 1].x
                        y: starItem.containmentMask.starPoints[modelData + 1].y
                    }
                }
                PathLine {
                    x: starItem.containmentMask.starPoints[0].x
                    y: starItem.containmentMask.starPoints[0].y
                }
            }
        }
    }
}

解説
この例では、starItemcontainmentMaskQtObject を設定し、その中に contains(point) 関数を定義しています。この関数は、与えられた point が、定義された starPoints(星形の頂点)で構成される多角形の内側にあるかどうかを判定するロジック(点と多角形の包含判定アルゴリズム、いわゆる「レイトレーシング法」)を含んでいます。これにより、見かけは四角い Rectangle が、実際に星形の領域でのみインタラクションするようになります。視覚的な星形は別の Shape で描画し、z: -1 で背面に配置することで、イベント領域との関連をわかりやすくしています。



Item.containmentMaskは特定のユースケースで非常に便利ですが、常にそれが最適な解決策とは限りません。状況によっては、他のQML機能やアプローチの方が適している場合があります。主な代替方法を以下に示します。

MouseArea を使用する

これは、QMLでポインタイベントを処理する最も一般的で基本的な方法です。MouseAreaは、その親アイテム内で特定の領域にイベントハンドラーを定義するために使用されます。

特徴

  • プロパティが豊富
    hoverEnabled, pressed, containsMouse, dragなど、マウスイベントに関連する多くの便利なプロパティとシグナルを提供します。
  • 複数定義
    1つの親アイテム内に複数のMouseAreaを配置し、異なる領域に異なるイベントハンドラーを設定できます。
  • シンプルさ
    簡単な四角いイベント領域を作成するのに非常に適しています。

containmentMaskの代替としての使用例
アイテムのクリック領域を小さくしたい場合、MouseAreaをそのアイテムの子として、希望するサイズと位置で配置します。

Rectangle {
    width: 200
    height: 200
    color: "lightblue"

    // Rectangle の見た目とは別に、小さなクリック可能な領域を定義
    MouseArea {
        anchors.centerIn: parent
        width: 100 // クリック領域の幅
        height: 100 // クリック領域の高さ
        onClicked: console.log("MouseArea clicked!")
        // debug: MouseArea の可視化 (通常は透明)
        // Rectangle { anchors.fill: parent; color: "rgba(255,0,0,0.3)"; z: -1 }
    }
}

containmentMaskとの比較

  • MouseAreaは子アイテムとして追加され、親の描画順とは独立してイベントを処理します。containmentMaskは親アイテム自体のヒットテストロジックを変更します。
  • MouseAreaは常に四角形の領域を定義します。containmentMaskShapeやカスタムcontains()で非長方形の領域を定義できます。
  • MouseAreaは「この領域がクリック可能」という考え方。containmentMaskは「このアイテムのヒットテストは、このマスクの形に従う」という考え方。

ポインタイベントハンドラー(TapHandler, HoverHandler など)の grabTarget

Qt 6以降で導入されたポインタイベントハンドラー(TapHandler, HoverHandler, DragHandler など)は、grabTargetというプロパティを持っています。これにより、ハンドラーがイベントを「掴む」対象を明示的に指定できます。

特徴

  • grabTarget
    複数のアイテムが重なっている場合など、特定のアイテムにイベントを割り当てたいときに便利です。
  • 柔軟なイベント伝播
    accepted プロパティなどと組み合わせて、イベントの伝播を細かく制御できます。
  • 宣言的
    イベント処理をより宣言的に記述できます。

containmentMaskの代替としての使用例
アイテムのイベントを、特定のサブコンポーネントのみに制限したいが、そのサブコンポーネントが常に表示されているわけではない場合など。

Rectangle {
    width: 200
    height: 200
    color: "lightseagreen"

    Rectangle {
        id: clickableRegion
        width: 100
        height: 100
        color: "yellow"
        anchors.centerIn: parent
    }

    // grabTarget を clickableRegion に設定することで、
    // Rectangle 全体ではなく clickableRegion の領域のみでタップが反応する
    TapHandler {
        grabTarget: clickableRegion // このプロパティが重要
        onTapped: console.log("TapHandler tapped on clickableRegion!")
    }
}

containmentMaskとの比較

  • grabTargetは四角形の領域に制限されますが、イベントハンドラーのcontains()メソッドをオーバーライドすれば、非長方形も可能です(ただし、containmentMaskほど直接的ではない)。
  • grabTargetは主にハンドラーのスコープを制限するために使われます。containmentMaskは、形状によるヒットテスト領域を定義するために使われます。
  • grabTargetは、イベントハンドラーが「どのアイテムのイベントを処理するか」を明示的に指定します。containmentMaskは、「そのアイテム自体のcontains()メソッドがどう振る舞うか」を定義します。

C++でカスタム QQuickItem を作成し contains() をオーバーライドする

最も強力で柔軟な方法です。QMLのItemは内部的にC++のQQuickItemクラスにマップされます。QQuickItemcontains()仮想関数をC++でオーバーライドすることで、非常に複雑なロジックに基づいてヒットテストを実行できます。

特徴

  • 再利用性
    カスタムのQMLタイプとして登録することで、他のQMLコンポーネントで再利用できます。
  • パフォーマンス
    複雑な計算をC++で行うことで、QMLスクリプトよりも高いパフォーマンスを期待できます。
  • 完全な制御
    C++の全機能を利用して、任意の形状やロジックでヒットテストを実装できます。

containmentMaskの代替としての使用例
非常に複雑なジオメトリ(例: ポリゴン、スプライン曲線)に対するヒットテストが必要な場合や、ヒットテストロジックが頻繁に呼び出される(例: ドラッグ中に常にヒットテストが行われる)場合に特に有効です。

// mycustomitem.h
#include <QtQuick/QQuickItem>
#include <QPointF>

class MyCustomItem : public QQuickItem
{
    Q_OBJECT
public:
    MyCustomItem(QQuickItem *parent = nullptr);

    // QQuickItem::contains() をオーバーライド
    bool contains(const QPointF &point) const override;

    // 必要に応じて、QMLから設定できるプロパティなどを追加
    Q_PROPERTY(QVariantList polygonPoints READ polygonPoints WRITE setPolygonPoints NOTIFY polygonPointsChanged)

signals:
    void polygonPointsChanged();

private:
    QVariantList m_polygonPoints;
    // ... その他のメンバー ...
};
// mycustomitem.cpp
#include "mycustomitem.h"
#include <QDebug>
#include <QPolygonF>

MyCustomItem::MyCustomItem(QQuickItem *parent)
    : QQuickItem(parent)
{
    // setFlag(ItemAcceptsDropsInDroppedState, true); // 必要に応じて
}

// 重要な contains メソッドの実装
bool MyCustomItem::contains(const QPointF &point) const
{
    // ここに任意のヒットテストロジックを記述
    // 例: 多角形の内側判定
    if (m_polygonPoints.isEmpty() || !QQuickItem::contains(point)) {
        return false; // まずは親の境界ボックスでフィルター
    }

    QPolygonF polygon;
    for (const QVariant &varPoint : m_polygonPoints) {
        polygon << varPoint.toPointF(); // QVariant を QPointF に変換
    }

    return polygon.containsPoint(point, Qt::OddEvenFill); // Qt の多角形包含判定を使用
}

QVariantList MyCustomItem::polygonPoints() const {
    return m_polygonPoints;
}

void MyCustomItem::setPolygonPoints(const QVariantList &polygonPoints) {
    if (m_polygonPoints == polygonPoints)
        return;
    m_polygonPoints = polygonPoints;
    emit polygonPointsChanged();
    update(); // 形状が変わったら再描画
}
// main.cpp (QMLに登録)
#include "mycustomitem.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    // MyCustomItem を QML に登録
    qmlRegisterType<MyCustomItem>("CustomComponents", 1, 0, "MyCustomItem");

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}
// main.qml (QMLからの使用例)
import QtQuick 2.15
import QtQuick.Window 2.15
import CustomComponents 1.0 // カスタムコンポーネントをインポート

Window {
    width: 640
    height: 480
    visible: true
    title: "Custom Item Contains Method"

    MyCustomItem {
        width: 300
        height: 300
        anchors.centerIn: parent
        color: "purple" // MyCustomItem に color プロパティを追加していれば有効

        // 星形の頂点をQMLから設定(MyCustomItemに polygonPoints プロパティが定義されている場合)
        polygonPoints: [
            Qt.point(150, 20),
            Qt.point(180, 100),
            Qt.point(280, 110),
            Qt.point(200, 170),
            Qt.point(230, 280),
            Qt.point(150, 220),
            Qt.point(70, 280),
            Qt.point(100, 170),
            Qt.point(20, 110),
            Qt.point(120, 100)
        ]

        TapHandler {
            onTapped: console.log("Custom item star tapped!")
        }
    }
}
  • C++のcontains()は、QMLとC++の知識が必要です。
  • C++のcontains()オーバーライドは、複雑なジオメトリ計算、非常に高いパフォーマンス要件、または既存のC++ライブラリを利用したい場合に最適です。
  • containmentMaskはQML内での迅速なプロトタイピングやシンプルな非長方形ヒットテストに適しています。

どの代替方法を選ぶべきか?

  • 非常に複雑な非長方形のヒットテスト、高いパフォーマンス要件、またはC++のジオメトリ処理ライブラリを利用したい場合
    C++でカスタムQQuickItemを作成し、contains()メソッドをオーバーライドするのが最善です。
  • QML内でカスタムの非長方形ロジックを定義したいが、パフォーマンスが最優先ではない場合
    Item.containmentMaskQtObject内のカスタムcontains()関数を使用できます。
  • QML内で非長方形のイベント領域を定義したいが、ロジックがそれほど複雑でない場合
    Item.containmentMaskShapeの組み合わせが適しています。
  • 四角いイベント領域で十分な場合
    MouseAreaやポインタイベントハンドラーのgrabTargetが最も簡単で効率的です。