QGraphicsSceneMouseEvent::posAtItem() を使用する


QGraphicsItem::isUnderMouse() 関数は、現在のマウスカーソル位置がグラフィックアイテム上にあるかどうかを判断します。これは、マウスイベント処理やアイテムとのインタラクションを実装する際に役立ちます。

戻り値

  • マウスカーソルがアイテム上ではない場合: false
  • マウスカーソルがアイテム上にある場合: true

class MyItem : public QGraphicsItem
{
public:
    MyItem(QGraphicsItem *parent = nullptr);

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    bool sceneEvent(QGraphicsSceneEvent *event) override;
};

MyItem::MyItem(QGraphicsItem *parent) : QGraphicsItem(parent)
{
    // アイテムの初期化処理
}

void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    // アイテムを描画する処理
}

bool MyItem::sceneEvent(QGraphicsSceneEvent *event)
{
    if (event->type() == QEvent::GraphicsItemMouseMove) {
        // マウスカーソルがアイテム上を移動した場合
        if (isUnderMouse()) {
            // アイテム上でのマウスカーソル移動処理
            qDebug() << "マウスカーソルがアイテム上を移動しました";
        }
    }

    return QGraphicsItem::sceneEvent(event);
}

この例では、MyItem クラスがマウスカーソルがアイテム上を移動した場合に qDebug() メッセージを出力するように実装されています。

  • マウスイベントの処理は、sceneEvent() メンバ関数内で実装する必要があります。
  • マウスカーソルがアイテムの子アイテム上にある場合も、isUnderMouse() 関数は true を返します。
  • isUnderMouse() 関数は、アイテムの boundingRect を基に判定を行います。そのため、アイテムの形状が複雑な場合は、正確な判定結果が得られない場合があります。


#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QPainter>
#include <QMouseEvent>

class MyItem : public QGraphicsItem
{
public:
    MyItem(QGraphicsItem *parent = nullptr);

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    bool sceneEvent(QGraphicsSceneEvent *event) override;
};

MyItem::MyItem(QGraphicsItem *parent) : QGraphicsItem(parent)
{
    // アイテムの初期化処理
    setFlag(QGraphicsItem::ItemIsSelectable);
    setFlag(QGraphicsItem::ItemIsFocusable);
}

void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    // アイテムを描画する処理
    painter->setBrush(m_color);
    painter->drawRect(boundingRect());
}

bool MyItem::sceneEvent(QGraphicsSceneEvent *event)
{
    if (event->type() == QEvent::GraphicsItemMouseMove) {
        // マウスカーソルがアイテム上を移動した場合
        if (isUnderMouse()) {
            // アイテムの色を変更
            m_color = QColor(Qt::red);
            update();
        } else {
            // アイテムの色を元に戻す
            m_color = QColor(Qt::white);
            update();
        }
    }

    return QGraphicsItem::sceneEvent(event);
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // シーンとビューを作成
    QGraphicsScene scene;
    QGraphicsView view(&scene);

    // アイテムを作成してシーンに追加
    MyItem *item = new MyItem;
    item->setPos(100, 100);
    scene.addItem(item);

    // ビューを表示
    view.resize(400, 300);
    view.show();

    return app.exec();
}

このコードを実行すると、白い矩形アイテムが表示されます。マウスカーソルをアイテムの上に移動すると、アイテムが赤色に変わります。

  • main() 関数は、アプリケーションのエントリーポイントです。この関数は、シーン、ビュー、アイテムを作成し、ビューを表示します。
  • sceneEvent() メンバ関数は、マウスイベントを処理します。この例では、isUnderMouse() 関数を使用して、マウスカーソルがアイテム上にあるかどうかを判断し、それに応じてアイテムの色を変更しています。
  • paint() メンバ関数は、アイテムを描画します。この例では、アイテムの色を m_color メンバ変数で設定しています。
  • MyItem クラスは、QGraphicsItem クラスを継承したカスタムアイテムクラスです。


QGraphicsSceneMouseEvent::posAtItem() を使用する

QGraphicsSceneMouseEvent::posAtItem() 関数は、マウスカーソルがアイテム上のどの位置にあるかを返すことができます。この情報を使用して、マウスカーソルがアイテムの境界内にあるかどうかを判断することができます。

bool MyItem::sceneEvent(QGraphicsSceneEvent *event)
{
    if (event->type() == QEvent::GraphicsItemMouseMove) {
        // マウスカーソルがアイテム上を移動した場合
        QPointF pos = event->posAtItem();
        if (boundingRect().contains(pos)) {
            // マウスカーソルがアイテムの境界内にある
            qDebug() << "マウスカーソルがアイテムの境界内にある";
        }
    }

    return QGraphicsItem::sceneEvent(event);
}

QPainterPath::contains() を使用する

QPainterPath::contains() 関数は、指定された点がパス内に含まれているかどうかを判断します。この方法を使用して、マウスカーソルがアイテムの形状内に含まれているかどうかを判断することができます。

bool MyItem::sceneEvent(QGraphicsSceneEvent *event)
{
    if (event->type() == QEvent::GraphicsItemMouseMove) {
        // マウスカーソルがアイテム上を移動した場合
        QPainterPath path;
        path.addRect(boundingRect());

        QPointF pos = event->posAtItem();
        if (path.contains(pos)) {
            // マウスカーソルがアイテムの形状内に含まれている
            qDebug() << "マウスカーソルがアイテムの形状内に含まれている";
        }
    }

    return QGraphicsItem::sceneEvent(event);
}

カスタム判定ロジックを実装する

上記の方法に加えて、アイテムの形状や要件に応じて、カスタム判定ロジックを実装することもできます。

それぞれの方法の利点と欠点

  • カスタム判定ロジック:
    • 利点: アイテムの形状や要件に合わせた柔軟な判定が可能
    • 欠点: ロジックの設計と実装が必要
  • QPainterPath::contains():
    • 利点: アイテムの形状に合わせた判定が可能
    • 欠点: 複雑な形状の場合はパス作成が複雑になる
  • QGraphicsSceneMouseEvent::posAtItem():
    • 利点: マウスカーソルのアイテム上での位置がわかる
    • 欠点: アイテムの形状が複雑な場合は判定が難しい

どの方法が最適かは、アイテムの形状や要件によって異なります。状況に応じて適切な方法を選択してください。

  • マウスカーソルの判定精度を高めるためには、QGraphicsScene::update() 関数を頻繁に呼び出す必要があります。
  • 上記の例では、マウスカーソルがアイテム上を移動した場合のみ判定を行っています。他のイベントハンドラで同様の判定を行うこともできます。