Qt Widgets:シーン座標とアイテム座標の変換をマスターしよう!QGraphicsSceneContextMenuEvent::scenePos()徹底解説(応用例付き)


QGraphicsSceneContextMenuEvent::scenePos()は、Qt WidgetsライブラリにおけるQGraphicsSceneContextMenuEventクラスのメソッドで、コンテキストメニューイベントが発生した時点におけるマウスカーソルのシーン座標を取得します。シーン座標とは、QGraphicsScene内のアイテム座標系における座標です。

用途

このメソッドは、コンテキストメニューを表示する位置を決定したり、アイテムとの相互作用を処理したりする際に役立ちます。例えば、以下の用途で使用できます。

  • アイテムとの距離に基づいてコンテキストメニューの項目を有効化/無効化する
  • アイテム上の特定のポイントを基準にコンテキストメニューを配置する
  • マウスカーソルが現在どのアイテムの上に存在しているかを判断する

使用方法

QGraphicsSceneContextMenuEvent::scenePos()メソッドを使用するには、以下の手順に従います。

  1. QGraphicsSceneContextMenuEventオブジェクトを取得します。これは、QGraphicsViewウィジェットのcontextMenuEvent()シグナルスロットに接続することで行うことができます。
  2. scenePos()メソッドを呼び出し、QPointF型の値を取得します。この値は、シーン座標系におけるX座標とY座標を表します。
void MyGraphicsView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QPointF scenePos = event->scenePos();
    qDebug() << "Scene position: " << scenePos;

    // アイテムとの相互作用を処理する
    QGraphicsItem *item = scene()->itemAt(scenePos);
    if (item) {
        // ...
    }
}
  • QGraphicsSceneContextMenuEvent::screenPos()メソッドは、スクリーン座標系におけるマウスカーソルの位置を取得します。
  • QGraphicsSceneContextMenuEvent::pos()メソッドは、ウィジェット座標系におけるマウスカーソルの位置を取得します。


void MyGraphicsView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QPointF scenePos = event->scenePos();
    QGraphicsItem *item = scene()->itemAt(scenePos);

    if (item) {
        qDebug() << "Mouse cursor is over item: " << item->objectName();

        // アイテムとの距離に基づいてコンテキストメニューの項目を有効化/無効化する
        if (item->type() == MyItemType) {
            MyItem *myItem = static_cast<MyItem *>(item);
            if (myItem->distanceToCursor() < 50) {
                // ...
            }
        }
    } else {
        qDebug() << "Mouse cursor is not over any item";
    }
}

例2: アイテム上の特定のポイントを基準にコンテキストメニューを配置する

void MyGraphicsView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QPointF scenePos = event->scenePos();
    QGraphicsItem *item = scene()->itemAt(scenePos);

    if (item) {
        QPointF itemPos = item->mapToScene(item->boundingRect().center());
        QMenu menu(this);

        // ...

        menu.exec(mapToGlobal(itemPos));
    } else {
        qDebug() << "Mouse cursor is not over any item";
    }
}
void MyGraphicsView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QPointF scenePos = event->scenePos();
    QGraphicsItem *item = scene()->itemAt(scenePos);

    if (item) {
        QMenu menu(this);

        // ...

        if (item->type() == MyItemType) {
            MyItem *myItem = static_cast<MyItem *>(item);
            if (myItem->distanceToCursor() < 50) {
                // ...
            } else {
                // ...
            }
        }

        menu.exec(mapToGlobal(event->pos()));
    } else {
        qDebug() << "Mouse cursor is not over any item";
    }
}


QGraphicsSceneContextMenuEvent::scenePos()は、コンテキストメニューイベントが発生した時点におけるマウスカーソルのシーン座標を取得する便利なメソッドですが、状況によっては代替方法が必要になる場合があります。

代替方法

以下に、QGraphicsSceneContextMenuEvent::scenePos()の代替方法をいくつか紹介します。

QGraphicsSceneMouseEvent::scenePos()を使用する

QGraphicsSceneContextMenuEventは、QGraphicsSceneMouseEventを継承しているため、scenePos()メソッドも使用できます。

void MyGraphicsView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QPointF scenePos = event->scenePos();

    // ...
}

QGraphicsScene::mouseGrabberItem()を使用する

QGraphicsSceneクラスのmouseGrabberItem()メソッドは、現在マウスカーソルを掴んでいるアイテムを取得します。このアイテムの座標をシーン座標に変換することで、マウスカーソルのシーン座標を取得できます。

void MyGraphicsView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QGraphicsItem *item = scene()->mouseGrabberItem();
    if (item) {
        QPointF scenePos = item->scenePos();

        // ...
    }
}

QGraphicsView::mapToScene()を使用する

QGraphicsViewクラスのmapToScene()メソッドは、ウィジェット座標をシーン座標に変換します。

void MyGraphicsView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QPointF scenePos = mapToScene(event->pos());

    // ...
}

カスタムイベントを使用する

上記の方法でうまくいかない場合は、カスタムイベントを使用することもできます。カスタムイベントは、独自のデータ構造を定義して、必要な情報をイベントに格納することができます。

class MyContextMenuEvent : public QGraphicsSceneContextMenuEvent
{
public:
    QPointF scenePos() const { return m_scenePos; }

private:
    QPointF m_scenePos;
};

void MyGraphicsView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    MyContextMenuEvent *myEvent = static_cast<MyContextMenuEvent *>(event);
    myEvent->setScenePos(mapToScene(event->pos()));

    // ...
}

選択の指針

どの方法を選択するかは、状況によって異なります。

  • より柔軟な制御が必要な場合は、QGraphicsSceneMouseEvent::scenePos(), QGraphicsScene::mouseGrabberItem(), QGraphicsView::mapToScene(), またはカスタムイベントを使用することを検討してください。
  • シンプルで分かりやすい方法が必要な場合は、QGraphicsSceneContextMenuEvent::scenePos()を使用するのがおすすめです。