Qt QGraphicsViewでマウス操作を制御!interactiveプロパティの活用法
QGraphicsViewとは?
まず、QGraphicsView
について簡単に説明します。
QtのGraphics Viewフレームワークは、2Dグラフィックスアイテム(図形、画像、テキストなど)を表示するための強力なツールです。このフレームワークは主に以下の3つの主要なクラスで構成されます。
- QGraphicsScene: 描画されるすべてのグラフィックスアイテムを保持する論理的なコンテナです。
- QGraphicsItem: シーンに配置される個々のグラフィックス要素(例:
QGraphicsRectItem
,QGraphicsEllipseItem
,QGraphicsPixmapItem
など)の基本クラスです。 - QGraphicsView:
QGraphicsScene
の内容を表示するためのウィジェットです。ビューは、シーンの一部または全体を表示でき、ズームや回転などの変換を適用することもできます。
QGraphicsView::interactive
とは?
QGraphicsView::interactive
プロパティは、ビューがユーザーの入力イベント(マウスイベントやキーボードイベントなど)を処理し、それらのイベントをシーンやアイテムに伝播するかどうかを決定します。
このプロパティがtrue
(デフォルト)の場合、QGraphicsView
は以下の対話的な操作を自動的に処理します。
- シーンへのイベント伝播: マウスイベントやキーボードイベントがシーンに伝播され、シーンが適切なアイテムにディスパッチする。
- アイテムとのインタラクション: アイテムがクリックされたり、ドラッグされたりしたときに、そのアイテムのイベントハンドラが呼び出される。
- アイテムの選択: マウスでクリックまたはドラッグしてアイテムを選択。
- マウスによるスクロール: マウスドラッグによるビューポートの移動。
一方、interactive
プロパティがfalse
に設定されている場合、QGraphicsView
はユーザー入力イベントを処理せず、シーンやアイテムにイベントを伝播しません。これは、ビューを単なる表示ウィジェットとして使用し、ユーザーがコンテンツと対話できないようにしたい場合に便利です。
interactive
プロパティを設定するには、setInteractive()
関数を使用します。
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(0, 0, 400, 300); // シーンのサイズを設定
// 四角形アイテムをシーンに追加
QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 100, 100);
rectItem->setPos(50, 50);
rectItem->setBrush(Qt::blue);
rectItem->setFlag(QGraphicsItem::ItemIsMovable); // ドラッグ可能にする
scene.addItem(rectItem);
QGraphicsView view;
view.setScene(&scene);
// interactiveをtrueに設定 (デフォルトなので通常は不要)
view.setInteractive(true); // これにより、アイテムをドラッグしたり、ビューをスクロールしたりできる
// もしユーザーの操作を無効にしたい場合は、以下のようにする
// view.setInteractive(false); // この場合、上記でItemIsMovableを設定してもアイテムはドラッグできない
view.setWindowTitle("Interactive QGraphicsView Example");
view.show();
return a.exec();
}
上記の例では、setInteractive(true)
がデフォルトで有効になっているため、青い四角形をマウスでドラッグして動かすことができます。もしview.setInteractive(false);
のコメントアウトを外すと、四角形はドラッグできなくなり、ビュー自体もスクロールできなくなります。
QGraphicsView::interactive
とは何か(再確認)
QGraphicsView::interactive
は、QGraphicsView
がユーザーのマウスやキーボード入力に対して対話的に応答するかどうかを制御するブール型のプロパティです。
false
: ビューはユーザー入力に反応せず、静的な表示のみを行います。イベントは通常、伝播されません。true
(デフォルト): ユーザーはビューをパン(移動)、ズーム、アイテムの選択、ドラッグなどの操作ができます。イベントはビュー、シーン、アイテムへと伝播されます。
一般的なエラーとトラブルシューティング
アイテムがドラッグできない、選択できない
問題: QGraphicsItem::ItemIsMovable
などのフラグを設定しているのに、アイテムが移動したり選択したりできない。
原因: QGraphicsView::interactive
がfalse
に設定されている可能性があります。interactive
がfalse
の場合、ビューはユーザー入力を処理しないため、アイテムレベルでのインタラクションも無効になります。
トラブルシューティング:
- コードを確認する:
view.setInteractive(false);
のような呼び出しがないか、コードベース全体を検索します。特に、GUIを初期化する部分や、特定の操作モードに切り替える部分で意図せずfalse
に設定されていることがあります。 QGraphicsView::setInteractive(true);
を呼び出す: これが最も一般的な解決策です。ビューがユーザー入力イベントを処理するように設定します。
ビューのパン(スクロール)やズームができない
問題: マウスドラッグでビューポートを移動したり、マウスホイールでズームしたりできない。
原因: QGraphicsView::interactive
がfalse
に設定されている可能性があります。ビュー自体の基本的なインタラクションもこのプロパティに依存します。
トラブルシューティング:
- カスタムのイベントフィルタやイベントハンドラを確認する:
QGraphicsView
やその親ウィジェットに、マウスイベントをインターセプトしたり、消費したりするカスタムのイベントフィルタやイベントハンドラが設定されていないか確認します。これらのハンドラが、ビューのデフォルトのインタラクションを妨げている可能性があります。- 例:
event->accept()
ではなくevent->ignore()
が呼ばれていないか、またはイベントが全く処理されていないか。
- 例:
QGraphicsView::setInteractive(true);
を呼び出す: ビューのインタラクティブ機能を有効にします。
カスタムのイベント処理が期待通りに動作しない
問題: QGraphicsItem
にmousePressEvent
やmouseMoveEvent
などのカスタムイベントハンドラを実装しているが、それらが呼ばれない。
原因:
QGraphicsView::interactive
がfalse
: 前述のとおり、これがfalse
だとイベントはアイテムまで到達しません。- アイテムのフラグが適切でない:
QGraphicsItem::ItemIsSelectable
やQGraphicsItem::ItemIsMovable
など、アイテムの特定のインタラクションに対応するフラグが設定されていない場合、その種のイベントは処理されないことがあります。 - イベントの伝播が中断されている:
QGraphicsScene
や他のアイテムがイベントを消費(event->accept()
を呼び出す)してしまい、目的のアイテムにイベントが到達していない可能性があります。 QGraphicsView::viewportEvent()
のオーバーライド: もしQGraphicsView
を継承し、viewportEvent()
をオーバーライドしている場合、その中でイベントを適切に処理し、必要に応じて基底クラスのメソッドを呼び出すか、イベントを無視(event->ignore()
)して通常の処理フローに戻す必要があります。間違った実装は、ビューのインタラクティブな振る舞いを壊す可能性があります。
トラブルシューティング:
event->ignore()
の使用: イベントを完全に処理しない場合は、event->ignore()
を呼び出して、他のイベントハンドラやデフォルトの処理がイベントを受け取れるようにします。誤ってevent->accept()
を呼び出してしまうと、イベントの伝播がそこで止まってしまいます。- デバッグ出力: イベントハンドラ(ビュー、シーン、アイテムの各レベル)にデバッグメッセージを追加し、イベントがどこまで伝播しているかを確認します。
- アイテムのフラグを確認:
item->setFlag(QGraphicsItem::ItemIsMovable);
のように、必要なフラグが設定されていることを確認します。 QGraphicsView::setInteractive(true);
を確認: 最も基本的なチェックです。
複数のビューが同じシーンを参照している場合の挙動
問題: 複数のQGraphicsView
が同じQGraphicsScene
を表示しているが、一方のビューでのインタラクションが他方のビューに反映されない、または予期しない挙動をする。
原因: 各QGraphicsView
インスタンスは、独自のinteractive
プロパティを持っています。片方のビューでsetInteractive(false)
を呼び出しても、もう一方のビューには影響しません。
トラブルシューティング:
- 連携が必要な場合: 複数のビューでインタラクションを同期させたい場合は、一方のビューで発生したイベントをキャッチし、もう一方のビューに対してプログラム的に変換や操作を行う必要があります(例:一方のビューのスクロールバーの値が変更されたら、もう一方のビューも同期させるなど)。
- 各ビューのプロパティを個別に設定: 複数のビューを使用する場合、それぞれのビューに対して
setInteractive()
を呼び出し、それぞれのインタラクション設定を明示的に行う必要があります。
- ドキュメントの参照: Qtの公式ドキュメントは、各クラスのプロパティや関数の詳細な情報を提供しています。疑問がある場合は、まずドキュメントを参照しましょう。
- デバッグの活用: イベントハンドラやプロパティの値をデバッグ出力で確認することは、問題の特定に非常に役立ちます。
- 明示的に
false
にする場合: ビューを完全に静的な表示専用として使用したい場合にのみ、setInteractive(false)
を呼び出します。 QGraphicsView::interactive
のデフォルト設定を理解する: デフォルトはtrue
なので、特別な理由がない限り明示的にtrue
を設定する必要はありません。
例1:interactive
がtrue
の場合(デフォルト動作)
この例では、QGraphicsView
のinteractive
プロパティがデフォルトのtrue
の状態です。これにより、ユーザーはマウスでアイテムをドラッグしたり、ビューポートをパン(移動)したりできます。
ファイル構成
main.cpp
コード
// main.cpp
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QDebug> // デバッグ出力用
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 1. QGraphicsSceneを作成
QGraphicsScene scene;
scene.setSceneRect(-200, -150, 400, 300); // シーンの論理的な範囲を設定
// 2. QGraphicsItemを作成し、シーンに追加
QGraphicsRectItem *rectItem = new QGraphicsRectItem(-50, -50, 100, 100);
rectItem->setBrush(QBrush(Qt::blue)); // 青色で塗りつぶす
rectItem->setPen(QPen(Qt::black, 2)); // 黒色の縁線
rectItem->setFlag(QGraphicsItem::ItemIsMovable); // これをtrueにするとドラッグ可能になる
rectItem->setFlag(QGraphicsItem::ItemIsSelectable); // 選択可能にする
// アイテムがクリックされたことを確認するカスタムクラス
class ClickableRect : public QGraphicsRectItem {
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override {
qDebug() << "Rect clicked at:" << event->pos(); // クリック座標を出力
QGraphicsRectItem::mousePressEvent(event); // 基底クラスのハンドラを呼び出し、ドラッグなどを有効にする
}
};
ClickableRect *clickableRectItem = new ClickableRect();
clickableRectItem->setRect(50, 50, 80, 80);
clickableRectItem->setBrush(QBrush(Qt::green));
clickableRectItem->setPen(QPen(Qt::darkGreen, 2));
clickableRectItem->setFlag(QGraphicsItem::ItemIsMovable);
clickableRectItem->setFlag(QGraphicsItem::ItemIsSelectable);
scene.addItem(rectItem);
scene.addItem(clickableRectItem);
// 3. QGraphicsViewを作成し、シーンを設定
QGraphicsView view;
view.setScene(&scene);
// 4. interactiveプロパティを設定 (デフォルトはtrueなので、この行がなくても同じ動作)
// view.setInteractive(true); // 明示的に設定しても良い
view.setWindowTitle("Interactive QGraphicsView Example (Interactive: true)");
view.show();
return a.exec();
}
解説
- 実行結果
青い四角形と緑の四角形をマウスで自由にドラッグでき、緑の四角形をクリックするとデバッグ出力にメッセージが表示されます。マウスドラッグでビューポートも移動(パン)できます。 QGraphicsView
のinteractive
プロパティはデフォルトでtrue
なので、明示的にsetInteractive(true)
を呼び出す必要はありませんが、コードの意図を明確にするために含めることもできます。ClickableRect
クラスでは、mousePressEvent
をオーバーライドして、アイテムがクリックされたときにデバッグメッセージを出力しています。interactive
がtrue
なので、このイベントハンドラが正常に呼び出されます。QGraphicsRectItem
のインスタンスを2つ作成し、それぞれItemIsMovable
とItemIsSelectable
フラグを設定しています。これにより、ユーザーはマウスでアイテムをドラッグして移動させたり、クリックして選択したりできるようになります。
この例では、QGraphicsView
のinteractive
プロパティを明示的にfalse
に設定します。これにより、ユーザーはビューやシーン内のアイテムと対話できなくなります。ビューは静的な表示のみを行います。
ファイル構成
main.cpp
コード
// main.cpp
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QDebug> // デバッグ出力用
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 1. QGraphicsSceneを作成
QGraphicsScene scene;
scene.setSceneRect(-200, -150, 400, 300); // シーンの論理的な範囲を設定
// 2. QGraphicsItemを作成し、シーンに追加
QGraphicsRectItem *rectItem = new QGraphicsRectItem(-50, -50, 100, 100);
rectItem->setBrush(QBrush(Qt::blue));
rectItem->setPen(QPen(Qt::black, 2));
rectItem->setFlag(QGraphicsItem::ItemIsMovable); // ドラッグ可能フラグを設定 (しかし、無効化される)
rectItem->setFlag(QGraphicsItem::ItemIsSelectable); // 選択可能フラグを設定 (しかし、無効化される)
// アイテムがクリックされたことを確認するカスタムクラス
class ClickableRect : public QGraphicsRectItem {
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override {
qDebug() << "Rect clicked at:" << event->pos(); // クリック座標を出力 (このメッセージは表示されないはず)
QGraphicsRectItem::mousePressEvent(event);
}
};
ClickableRect *clickableRectItem = new ClickableRect();
clickableRectItem->setRect(50, 50, 80, 80);
clickableRectItem->setBrush(QBrush(Qt::green));
clickableRectItem->setPen(QPen(Qt::darkGreen, 2));
clickableRectItem->setFlag(QGraphicsItem::ItemIsMovable);
clickableRectItem->setFlag(QGraphicsItem::ItemIsSelectable);
scene.addItem(rectItem);
scene.addItem(clickableRectItem);
// 3. QGraphicsViewを作成し、シーンを設定
QGraphicsView view;
view.setScene(&scene);
// 4. interactiveプロパティをfalseに設定
view.setInteractive(false); // ★ここが重要★
view.setWindowTitle("Interactive QGraphicsView Example (Interactive: false)");
view.show();
return a.exec();
}
解説
- 実行結果
青い四角形と緑の四角形が表示されますが、これらをマウスでドラッグしたり選択したりすることはできません。緑の四角形をクリックしてもデバッグ出力にメッセージは表示されません。ビューポートもマウスで移動できません。 ClickableRect
のmousePressEvent
も呼び出されません。ビューがイベントを処理しないため、イベントがアイテムに到達しないからです。QGraphicsRectItem
にはItemIsMovable
やItemIsSelectable
フラグが設定されていますが、QGraphicsView::interactive
がfalse
のため、これらのフラグは効果がありません。アイテムをドラッグしたり選択したりすることはできません。- この例では、
view.setInteractive(false);
を呼び出しています。
これらの例からわかるように、QGraphicsView::interactive
プロパティは、QGraphicsView
とそのコンテンツのユーザーインタラクション全体を制御する非常に強力な設定です。
- falseの場合
ビューを単なる静的な表示領域として使用し、ユーザーがコンテンツと対話できないようにしたい場合に設定します。例えば、背景画像を表示するだけの場合や、別のUI要素でビューの操作を完全に制御する場合などに使用されます。 - trueの場合
ユーザーがビューポートをパンしたり、ズームしたり、シーン内のアイテムと対話したりできるようにしたい場合に設定します(デフォルト)。
QGraphicsView::interactive
の代替・連携方法
QGraphicsView::interactive
を false
に設定するだけでなく、特定のインタラクションを無効にしたり、独自のインタラクションを実装したりするための方法は以下の通りです。
QGraphicsView::setDragMode() の利用
setDragMode()
は、マウスドラッグに対するビューのデフォルトの挙動を制御します。interactive
が true
の場合に特に有用です。
QGraphicsView::RubberBandDrag
: ドラッグでラバーバンド(選択範囲を示す矩形)が表示され、その範囲内のアイテムが選択されます。QGraphicsView::ScrollHandDrag
: マウスカーソルが手の形に変わり、ドラッグでビューポートがパンされます。これはデフォルトの動作です。QGraphicsView::NoDrag
: マウスドラッグで何も起こりません。ビューのパン(移動)が無効になります。アイテムのドラッグは、QGraphicsItem::ItemIsMovable
が設定されていれば引き続き可能です。
使い分け: ビューのパン機能を無効にしたいが、アイテムのドラッグや選択は有効にしたい場合にsetDragMode(QGraphicsView::NoDrag)
が役立ちます。
例:
// ビューのパンを無効にするが、アイテムのドラッグは可能にする
view.setInteractive(true); // アイテムのインタラクションは有効にする
view.setDragMode(QGraphicsView::NoDrag); // ビューのパンを無効にする
QGraphicsView のイベントハンドラのオーバーライド
QGraphicsView
をサブクラス化し、マウスやキーボードのイベントハンドラをオーバーライドすることで、ビューレベルでのインタラクションを完全に制御できます。interactive
が false
の場合でも、オーバーライドしたメソッドは呼び出されます。
主要なイベントハンドラ:
keyReleaseEvent(QKeyEvent *event)
keyPressEvent(QKeyEvent *event)
wheelEvent(QWheelEvent *event)
(マウスホイールによるズーム/スクロール)mouseReleaseEvent(QMouseEvent *event)
mouseMoveEvent(QMouseEvent *event)
mousePressEvent(QMouseEvent *event)
これらのメソッド内で、必要な処理を行い、イベントを無視(event->ignore()
)するか、消費(event->accept()
)するかを決定します。
例:
QGraphicsView
のズーム機能をカスタムで実装する例
// MyGraphicsView.h
#include <QGraphicsView>
#include <QWheelEvent>
#include <QDebug>
class MyGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
MyGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr)
: QGraphicsView(scene, parent)
{
// デフォルトのズーム/パンを無効にするため、interactiveはfalseに設定しない
// もしくは、interactiveをtrueにしつつ、wheelEventのみをカスタムする
}
protected:
void wheelEvent(QWheelEvent *event) override
{
// マウスホイールによるズームをカスタム実装
qreal scaleFactor = 1.15; // ズーム倍率
if (event->angleDelta().y() > 0) {
// ホイールアップ (ズームイン)
scale(scaleFactor, scaleFactor);
} else {
// ホイールダウン (ズームアウト)
scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}
event->accept(); // イベントを消費し、親クラスの処理を停止
qDebug() << "Custom zoom applied.";
}
// デフォルトのパン機能を無効にしたい場合
void mousePressEvent(QMouseEvent *event) override
{
if (event->button() == Qt::LeftButton) {
// 左クリックでのドラッグによるパンを無効にする
// 基底クラスのmousePressEventは呼び出さない
qDebug() << "Left mouse button pressed, but pan is disabled.";
event->accept(); // イベントを消費
} else {
QGraphicsView::mousePressEvent(event); // その他のボタンはデフォルト処理
}
}
};
// main.cpp
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
// #include "MyGraphicsView.h" // 上記のMyGraphicsViewクラスをインクルード
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(-200, -150, 400, 300);
QGraphicsRectItem *rectItem = new QGraphicsRectItem(-50, -50, 100, 100);
rectItem->setBrush(QBrush(Qt::blue));
rectItem->setFlag(QGraphicsItem::ItemIsMovable); // アイテムはドラッグ可能
scene.addItem(rectItem);
MyGraphicsView view(&scene);
view.setInteractive(true); // アイテムのインタラクションは有効にしておく
// view.setDragMode(QGraphicsView::NoDrag); // これでもパンを無効にできる
view.setWindowTitle("Custom Interactive QGraphicsView Example");
view.show();
return a.exec();
}
解説: この例では、MyGraphicsView
を継承し、wheelEvent
をオーバーライドしてカスタムズームを実装しています。mousePressEvent
もオーバーライドすることで、左クリックでのドラッグによるパンを無効にしています。他のイベント(アイテムのドラッグなど)はsetInteractive(true)
によってデフォルトで有効のままです。
イベントフィルタの利用
QObject::installEventFilter()
を使用して、QGraphicsView
やその viewport()
にイベントフィルタをインストールすることもできます。これにより、特定のイベントタイプのみをインターセプトし、処理することができます。
使い分け:
QGraphicsView
を継承せずに特定のイベント処理をカスタマイズしたい場合。
例:
// main.cpp (MyEventFilter.h, MyEventFilter.cpp を別途作成しても良い)
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QDebug>
#include <QEvent>
#include <QMouseEvent>
#include <QWheelEvent>
// カスタムイベントフィルタクラス
class MyEventFilter : public QObject
{
Q_OBJECT
public:
explicit MyEventFilter(QObject *parent = nullptr) : QObject(parent) {}
protected:
bool eventFilter(QObject *obj, QEvent *event) override
{
if (obj->inherits("QGraphicsView")) { // もしくは obj == view.viewport()
if (event->type() == QEvent::Wheel) {
QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
QGraphicsView *view = qobject_cast<QGraphicsView*>(obj);
if (view) {
qreal scaleFactor = 1.15;
if (wheelEvent->angleDelta().y() > 0) {
view->scale(scaleFactor, scaleFactor);
} else {
view->scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}
qDebug() << "Event filter custom zoom applied.";
return true; // イベントを消費
}
} else if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
qDebug() << "Event filter caught left mouse press, pan disabled.";
return true; // イベントを消費し、デフォルトのパンを無効にする
}
}
}
return QObject::eventFilter(obj, event); // 他のイベントは通常通り処理
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(-200, -150, 400, 300);
QGraphicsRectItem *rectItem = new QGraphicsRectItem(-50, -50, 100, 100);
rectItem->setBrush(QBrush(Qt::blue));
rectItem->setFlag(QGraphicsItem::ItemIsMovable);
scene.addItem(rectItem);
QGraphicsView view(&scene);
view.setInteractive(true); // アイテムのインタラクションは有効にしておく
// イベントフィルタをビューのビューポートにインストール
MyEventFilter *filter = new MyEventFilter(&view); // 親をviewにして寿命を管理
view.viewport()->installEventFilter(filter); // view そのものではなく、viewport() にインストールするのが一般的
view.setWindowTitle("Event Filter QGraphicsView Example");
view.show();
return a.exec();
}
#include "main.moc" // Q_OBJECT マクロを含むクラスのために必要
解説: MyEventFilter
クラスを作成し、eventFilter
メソッドでホイールイベントとマウスプレスイベントを処理しています。view.viewport()->installEventFilter(filter);
で、このフィルタをビューポートに適用しています。これにより、QGraphicsView
の継承なしに特定のインタラクションをカスタマイズできます。
アイテムレベルでのインタラクション制御
QGraphicsItem
にも個別のインタラクションフラグやイベントハンドラがあります。
QGraphicsItem::mousePressEvent()
,mouseMoveEvent()
,mouseReleaseEvent()
,hoverEnterEvent()
,keyPressEvent()
など: アイテム固有のイベント処理を実装。QGraphicsItem::ItemIsFocusable
: アイテムがキーボードフォーカスを受け取るようにする。QGraphicsItem::ItemIsSelectable
: アイテムを選択可能にする。QGraphicsItem::ItemIsMovable
: アイテムをドラッグ可能にする。
使い分け: ビュー全体のインタラクションは残しつつ、特定のアイテムのインタラクションのみを無効にしたり、カスタマイズしたりする場合。
例:
// main.cpp (一部のみ抜粋)
// ... QGraphicsScene と QGraphicsView の設定は省略 ...
// ドラッグできないがクリックできるアイテム
class NonMovableClickableRect : public QGraphicsRectItem {
public:
NonMovableClickableRect(qreal x, qreal y, qreal w, qreal h, QGraphicsItem *parent = nullptr)
: QGraphicsRectItem(x, y, w, h, parent) {
setBrush(QBrush(Qt::red));
setFlag(QGraphicsItem::ItemIsSelectable); // 選択は可能
// setFlag(QGraphicsItem::ItemIsMovable); // ドラッグフラグは設定しない
}
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override {
qDebug() << "Non-movable rect clicked!";
QGraphicsRectItem::mousePressEvent(event); // 基底クラスの処理も呼び出す
}
};
// シーンにアイテムを追加
NonMovableClickableRect *nonMovableRect = new NonMovableClickableRect(10, 10, 80, 80);
scene.addItem(nonMovableRect);
// ... view.show() など ...
解説: NonMovableClickableRect
はItemIsMovable
フラグを持たず、ドラッグできません。しかし、mousePressEvent
をオーバーライドしているため、クリックには応答します。
setEnabled(false) の利用
最もシンプルな方法ですが、最も広範な影響があります。
view.setEnabled(false)
: ビュー全体を無効化します。すべてのマウスイベント、キーボードイベントがビューに対して無効になり、見た目もグレーアウトされます。
使い分け: ビューを一時的にユーザー操作から隔離し、完全に非対話的にしたい場合に適しています。
例:
QGraphicsView view(&scene);
view.show();
// 5秒後にビューを無効化する例
QTimer::singleShot(5000, [&]() {
view.setEnabled(false);
qDebug() << "QGraphicsView is now disabled.";
});
- ビューを一時的に完全にユーザー操作から隔離したい:
setEnabled(false)
- 特定のアイテムのインタラクションのみを制御したい:
QGraphicsItem
のフラグやイベントハンドラ (setFlag
,mousePressEvent
など) - ビューのデフォルトのインタラクションを維持しつつ、特定のカスタム操作を追加したい:
QGraphicsView
のイベントハンドラをオーバーライドし、必要に応じて基底クラスのメソッドを呼び出す。 - ビューのパン/ズームなどのデフォルトの挙動を無効にしたいが、アイテムのインタラクションは残したい:
QGraphicsView::setDragMode(QGraphicsView::NoDrag)
や、QGraphicsView
のイベントハンドラをオーバーライド (wheelEvent
やmousePressEvent
など) - ビュー全体の基本的な対話性(パン、ズーム、アイテムの選択/移動)を一括で有効/無効にしたい:
QGraphicsView::setInteractive()