【Qt】QGraphicsView resizeAnchorの代替手段 - カスタムリサイズ制御のプログラミング例
resizeAnchor
とは何か?
QGraphicsView
は、QGraphicsScene
の内容を表示するウィジェットです。ユーザーがビューのサイズを変更したり、ウィンドウのサイズを変更してビューのサイズが変わったりする際に、表示されているシーンの内容がどのように再配置されるかを制御するのがresizeAnchor
の役割です。
このプロパティはQGraphicsView::ViewportAnchor
型の値を取ります。主な値は以下の通りです。
-
QGraphicsView::AnchorUnderMouse
- マウスポインターの下にあるシーンの点が固定されます。これは、ユーザーがインタラクティブにビューのサイズを変更する際(例えば、ウィンドウの角をドラッグしてリサイズする場合など)に非常に便利です。マウスポインターの下にあるオブジェクトが、ビューのサイズ変更後もマウスポインターの下に留まるように、ビューポートが調整されます。CADソフトウェアなどでズームイン・ズームアウトする際によく見られる挙動です。
-
QGraphicsView::AnchorViewCenter
- ビューポートの中心が固定されます。ビューのサイズが変更されると、その中心にあるシーンの領域が常にビューの中心に表示され続けるように、ビューポートが移動・拡大・縮小されます。これにより、ビューの中心にあるものが常に表示されるという意図に合致します。
-
- アンカー(基準点)を設定しません。ビューのサイズが変更されても、シーンの表示位置は変更されません。拡大・縮小は、シーンの中心に対して行われることが多いですが、厳密な固定点はありません。結果として、シーンの端の方に表示されているアイテムがビューから外れてしまうことがあります。
なぜ重要なのか?
resizeAnchor
は、ユーザーエクスペリエンスに大きく影響します。
- レイアウトの維持
ビューの中心を固定したい場合や、特定のアイテムを常に表示しておきたい場合に、適切なアンカーを設定することで意図しないスクロールやレイアウトの崩れを防ぐことができます。 - 直感的なリサイズ
特にAnchorUnderMouse
は、ユーザーが直感的に期待するリサイズ挙動を提供し、特定の箇所に注目しながらビューを拡大・縮小する際に役立ちます。
QGraphicsView
オブジェクトのsetResizeAnchor()
メソッドを使って設定します。
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(0, 0, 800, 600); // シーンのサイズを設定
// シーンにアイテムを追加
QGraphicsRectItem *rect = new QGraphicsRectItem(100, 100, 200, 150);
rect->setBrush(Qt::blue);
scene.addItem(rect);
QGraphicsRectItem *anotherRect = new QGraphicsRectItem(500, 400, 100, 100);
anotherRect->setBrush(Qt::red);
scene.addItem(anotherRect);
QGraphicsView view(&scene);
// ここで resizeAnchor を設定
// 例1: ビューの中心を固定
// view.setResizeAnchor(QGraphicsView::AnchorViewCenter);
// 例2: マウスカーソルの位置を固定(よりインタラクティブ)
view.setResizeAnchor(QGraphicsView::AnchorUnderMouse);
// デフォルト (NoAnchor) の場合は何も設定しないか、以下を呼び出す
// view.setResizeAnchor(QGraphicsView::NoAnchor);
view.setWindowTitle("QGraphicsView Resize Anchor Example");
view.show();
return a.exec();
}
resizeAnchor
はビューのリサイズ時の挙動を制御する便利な機能ですが、期待通りの動作をしない場合にいくつかの一般的な問題が発生することがあります。
想定外のスクロール/表示範囲の変化
問題
ビューのサイズを変更した際に、表示されていたアイテムがビューの外に出てしまったり、ビューポートが意図しない方向にスクロールしてしまったりする。特にQGraphicsView::NoAnchor
を使用している場合に顕著です。
原因
- シーンのサイズとビューのサイズの関係
シーンが非常に大きい場合や、ビューが非常に小さい場合に、わずかなリサイズでも表示範囲が大きく変わることがあります。 - NoAnchorの動作を誤解している
NoAnchor
は、ビューのリサイズ時にビューポートの位置を固定しません。つまり、ビューの左上隅が固定されるわけではないため、ビューが拡大すると中心がずれてしまい、ビューポートの相対的な位置は保たれても、ユーザーが見ていた領域がビューの外に出てしまうことがあります。
トラブルシューティング
- fitInView()の使用
特定のアイテムやシーン全体をビューにフィットさせたい場合は、QGraphicsView::fitInView()
を使用することを検討します。これは初期表示や、特定のアクション後の表示調整に役立ちます。 - シーンの範囲の確認
QGraphicsScene::sceneRect()
が適切に設定されているか確認します。シーンの範囲が小さすぎると、ビューがその範囲を超えて表示しようとしたときに問題が生じることがあります。 - 適切なresizeAnchorの選択
ユーザーがどこに注目しているかを考慮し、最も適切なアンカーを設定します。- QGraphicsView::AnchorViewCenter
ビューの中心に表示されている内容を常に維持したい場合に適しています。 - QGraphicsView::AnchorUnderMouse
ユーザーがマウスでリサイズ操作を行っており、マウスポインターの下にあるものを維持したい場合に非常に有効です。これにより、ユーザーは直感的に「拡大したい場所」をコントロールできます。
- QGraphicsView::AnchorViewCenter
AnchorUnderMouseが期待通りに機能しない
問題
setResizeAnchor(QGraphicsView::AnchorUnderMouse)
を設定したにもかかわらず、マウスカーソルの位置にあるものが固定されず、他のアンカーと同じような挙動になる。
原因
- リサイズ操作のトリガー
マウスを使わないリサイズ操作(例: プログラムからのresize()
呼び出し、自動レイアウトによるリサイズ)では、AnchorUnderMouse
は期待通りに機能しません。このアンカーは、ユーザーがインタラクティブにマウスでリサイズするシナリオのために設計されています。 - マウスイベントの捕捉
AnchorUnderMouse
は、リサイズ操作中にマウスイベント(特にQResizeEvent
と同時に発生するマウス位置)に依存します。もし、ビューの親ウィジェットや他のウィジェットがマウスイベントを消費してしまい、QGraphicsView
が正しいマウス位置を取得できていない可能性があります。
トラブルシューティング
- 他のアンカーとの比較
AnchorUnderMouse
が機能しないと感じる場合、一時的にAnchorViewCenter
など他のアンカーを設定して、ビューがリサイズイベント自体には反応しているかを確認します。 - イベントフィルタリングの確認
もし、ビューやその親にイベントフィルターが設定されている場合、マウス関連のイベントが意図せずブロックされていないか確認します。 - インタラクティブなリサイズでテスト
マウスを使って手動でウィンドウの端をドラッグしてリサイズし、挙動を確認します。プログラムからのリサイズではこのアンカーの恩恵を受けにくいことを理解しておきましょう。
ズーム操作との連携がうまくいかない
問題
resizeAnchor
はリサイズ時の挙動を制御するが、マウスホイールなどによるズーム操作(拡大・縮小)と組み合わせて使用すると、期待通りのズーム挙動にならないことがある。
原因
- カスタムズームロジックとの競合
独自のズームロジック(例えば、マウスホイールでズームし、その際にマウス位置を固定するようなロジック)を実装している場合、resizeAnchor
とは別にそのロジックを考慮する必要があります。 - ズームとリサイズの混同
resizeAnchor
はビューのサイズ変更時に適用されるものです。ズームは通常、scale()
メソッドなどを使ってビューの変換行列を変更することで行われます。これらは異なる操作であり、直接的な関連はありません。
トラブルシューティング
- 両者の役割の理解
resizeAnchor
はビューのウィジェットサイズが変化したときにシーンのどこを表示し続けるかを制御します。ズームはビューの表示倍率を変更します。これらは独立して機能することを理解し、それぞれ適切な設定を行う必要があります。 - ズームロジックの確認
ズーム操作に関しては、通常mapToScene()
やmapFromScene()
を使用してマウス位置をシーン座標に変換し、その点を中心にscale()
を適用します。このロジックが正しく実装されているかを確認します。// マウスホイールイベントでのズーム例 void MyGraphicsView::wheelEvent(QWheelEvent *event) { setTransformationAnchor(QGraphicsView::AnchorUnderMouse); // ズームの中心をマウス位置に設定 double scaleFactor = 1.15; // ズーム倍率 if (event->angleDelta().y() > 0) { // スクロールアップ (ズームイン) scale(scaleFactor, scaleFactor); } else { // スクロールダウン (ズームアウト) scale(1.0 / scaleFactor, 1.0 / scaleFactor); } setTransformationAnchor(QGraphicsView::NoAnchor); // 元に戻すか、他のアンカーを設定 }
setTransformationAnchor()
はズームなどの変換操作の中心を設定するものであり、setResizeAnchor()
とは別物です。
QGraphicsViewのサブクラス化と描画イベントの競合
問題
QGraphicsView
をサブクラス化し、resizeEvent()
をオーバーライドしてカスタム描画やレイアウト処理を行っている場合、resizeAnchor
の動作と衝突することがある。
原因
- resizeEvent()での不適切な処理
resizeEvent()
内で、QGraphicsView
が本来行うべき内部的なビューポート調整ロジックを妨害するような処理を行っている可能性があります。
トラブルシューティング
- デバッグ出力の活用
resizeEvent()
内でqDebug()
を使って、ビューのサイズやビューポートの矩形、シーンの矩形などを出力し、期待通りの値になっているか確認します。 - QGraphicsView::resizeEvent()の呼び出し
カスタムのresizeEvent()
をオーバーライドする場合でも、必ず基底クラスのQGraphicsView::resizeEvent(event);
を呼び出すようにしてください。これにより、resizeAnchor
を含むQGraphicsView
の標準的なリサイズ処理が実行されます。
QGraphicsView::resizeAnchor
に関するトラブルのほとんどは、その役割と各アンカーの具体的な動作を正確に理解していないことに起因します。
- ズーム操作とリサイズ操作は異なるものであり、それぞれ
setTransformationAnchor()
とsetResizeAnchor()
で制御されることを明確に理解する。 - 次に、ユーザーがどのようなリサイズ操作を期待するかを考慮し、最も適切なアンカーを選択する。
- まず、各アンカーの挙動を理解する。
これらの例では、基本的なQGraphicsView
とQGraphicsScene
を設定し、シーン内にいくつかの矩形アイテムを配置します。その後、setResizeAnchor()
を使って、ビューのリサイズ挙動を変化させます。
例1: QGraphicsView::NoAnchor
(デフォルトの挙動)
NoAnchor
はresizeAnchor
のデフォルト値です。この場合、ビューポートの位置はリサイズ時に「固定」されません。ビューが大きくなると、シーンの既存の表示領域はそのまま残り、新しい領域が追加されます。ビューが縮小すると、表示領域が削られます。これにより、ビューの左上隅に表示されていたアイテムが、リサイズ後もその位置に「見える」ことが多いですが、全体的な表示範囲は中心から外れていくように感じられます。
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QDebug> // デバッグ出力用
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// シーンの作成
QGraphicsScene scene;
scene.setSceneRect(-400, -300, 800, 600); // 中心を(0,0)にするため負の座標から開始
// シーンにアイテムを追加
// 中心に大きな青い四角
QGraphicsRectItem *centerRect = new QGraphicsRectItem(-50, -50, 100, 100);
centerRect->setBrush(Qt::blue);
centerRect->setPen(QPen(Qt::black, 2));
scene.addItem(centerRect);
// 右上隅に赤い四角
QGraphicsRectItem *topRightRect = new QGraphicsRectItem(300, -250, 50, 50);
topRightRect->setBrush(Qt::red);
topRightRect->setPen(QPen(Qt::black, 2));
scene.addItem(topRightRect);
// 左下隅に緑の四角
QGraphicsRectItem *bottomLeftRect = new QGraphicsRectItem(-350, 200, 70, 70);
bottomLeftRect->setBrush(Qt::green);
bottomLeftRect->setPen(QPen(Qt::black, 2));
scene.addItem(bottomLeftRect);
// ビューの作成
QGraphicsView view(&scene);
view.setWindowTitle("NoAnchor Example");
view.resize(600, 400); // 初期サイズを設定
// QGraphicsView::NoAnchor を明示的に設定 (デフォルトなので通常は不要)
view.setResizeAnchor(QGraphicsView::NoAnchor);
// シーンの中心がビューの中心にくるように設定(初期表示時のみ)
// resizeAnchorとは異なることに注意
view.centerOn(0, 0);
view.show();
return a.exec();
}
実行結果と解説
このコードを実行し、ウィンドウのサイズを変更してみてください。特にウィンドウを拡大したり縮小したりすると、ビューの左上隅(あるいはビューポートの初期位置)が固定されているかのように見え、中心の青い四角や端の赤い・緑の四角がビューポートから外れたり、ビューポートの端に追いやられたりする様子が分かります。新しいスペースは「右と下」に追加され、削除されるスペースは「右と下」から削除されるような挙動になります。
例2: QGraphicsView::AnchorViewCenter
AnchorViewCenter
を設定すると、ビューのサイズが変更されたときに、ビューポートの中心が常にシーンの同じ点に位置するように調整されます。これにより、ビューの中心に表示されていたものが、リサイズ後も常に中心に表示され続けるという直感的な挙動になります。
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(-400, -300, 800, 600); // 例1と同じシーン設定
QGraphicsRectItem *centerRect = new QGraphicsRectItem(-50, -50, 100, 100);
centerRect->setBrush(Qt::blue);
centerRect->setPen(QPen(Qt::black, 2));
scene.addItem(centerRect);
QGraphicsRectItem *topRightRect = new QGraphicsRectItem(300, -250, 50, 50);
topRightRect->setBrush(Qt::red);
topRightRect->setPen(QPen(Qt::black, 2));
scene.addItem(topRightRect);
QGraphicsRectItem *bottomLeftRect = new QGraphicsRectItem(-350, 200, 70, 70);
bottomLeftRect->setBrush(Qt::green);
bottomLeftRect->setPen(QPen(Qt::black, 2));
scene.addItem(bottomLeftRect);
QGraphicsView view(&scene);
view.setWindowTitle("AnchorViewCenter Example");
view.resize(600, 400);
// ★ここが変更点★
view.setResizeAnchor(QGraphicsView::AnchorViewCenter);
view.centerOn(0, 0); // シーンの中心をビューの中心に
view.show();
return a.exec();
}
実行結果と解説
このコードを実行し、ウィンドウのサイズを変更してみてください。NoAnchor
の例とは異なり、中央の青い四角が常にビューポートの中央付近に留まるように見えます。ビューを拡大すると、中央から均等に新しい表示領域が広がり、縮小すると均等に表示領域が狭まります。これは、シーンの中心に特に注目したい場合に非常に便利です。
例3: QGraphicsView::AnchorUnderMouse
AnchorUnderMouse
は、ユーザーがマウスを使ってビューのサイズを変更するときに最も効果を発揮します。この設定では、リサイズ操作を開始した時点のマウスカーソルの下にあるシーンの点が、リサイズ後もその点に留まるようにビューポートが調整されます。これにより、ユーザーは「ここを拡大(縮小)したい」という直感的な操作が可能になります。
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(-400, -300, 800, 600); // 例1と同じシーン設定
QGraphicsRectItem *centerRect = new QGraphicsRectItem(-50, -50, 100, 100);
centerRect->setBrush(Qt::blue);
centerRect->setPen(QPen(Qt::black, 2));
scene.addItem(centerRect);
QGraphicsRectItem *topRightRect = new QGraphicsRectItem(300, -250, 50, 50);
topRightRect->setBrush(Qt::red);
topRightRect->setPen(QPen(Qt::black, 2));
scene.addItem(topRightRect);
QGraphicsRectItem *bottomLeftRect = new QGraphicsRectItem(-350, 200, 70, 70);
bottomLeftRect->setBrush(Qt::green);
bottomLeftRect->setPen(QPen(Qt::black, 2));
scene.addItem(bottomLeftRect);
QGraphicsView view(&scene);
view.setWindowTitle("AnchorUnderMouse Example");
view.resize(600, 400);
// ★ここが変更点★
view.setResizeAnchor(QGraphicsView::AnchorUnderMouse);
view.centerOn(0, 0); // シーンの中心をビューの中心に
view.show();
return a.exec();
}
実行結果と解説
このコードを実行し、マウスでウィンドウの端(特に右下隅など)をドラッグしてサイズを変更してみてください。
- マウスが赤い四角の上にある状態でリサイズ
赤い四角がマウスカーソルの位置に固定されたまま、ビューが拡大・縮小されるように見えます。 - マウスが青い四角の上にある状態でリサイズ
青い四角がビューポートの中央付近に固定されたまま、ビューが拡大・縮小されるように見えます。
この挙動は、ユーザーが特定の場所を「ピン留め」したままビューのサイズを変更したい場合に非常に強力です。CADソフトウェアや画像編集ソフトウェアなどでよく見られるインタラクティブな挙動を実現できます。
主に以下の方法が考えられます。
-
QGraphicsView::resizeEvent()のオーバーライド
これは最も直接的な方法で、QGraphicsView
をサブクラス化し、resizeEvent()
メソッドを独自に実装することで、ビューのサイズ変更時に発生するイベントを捕捉し、完全にカスタムなロジックを適用できます。-
用途
- 特定のアイテムを常にビューの中心に表示し続けたい場合。
- ビューのサイズ変更に合わせて、シーンを特定の比率で拡大・縮小したい場合(例:
fitInView()
のカスタム実装)。 - ビューポートの移動やズームを、
resizeAnchor
が提供する以上の細かさで制御したい場合。
-
実装例
#include <QApplication> #include <QGraphicsView> #include <QGraphicsScene> #include <QGraphicsRectItem> #include <QResizeEvent> // QResizeEvent を使うために必要 // QGraphicsView をサブクラス化 class MyGraphicsView : public QGraphicsView { public: MyGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr) : QGraphicsView(scene, parent) { // 必要に応じて初期設定 // setResizeAnchor(QGraphicsView::NoAnchor); // カスタム制御のためNoAnchorに設定することも可能 } protected: void resizeEvent(QResizeEvent *event) override { // 基底クラスの resizeEvent を呼び出すことで、QGraphicsViewの標準的な処理(スクロールバーの調整など)を維持する QGraphicsView::resizeEvent(event); // --- ここからカスタムロジック --- // 例1: シーン全体を常にビューにフィットさせる // シーンのバウンディングボックスを取得 // QRectF sceneRect = scene()->itemsBoundingRect(); // fitInView(sceneRect, Qt::KeepAspectRatio); // 例2: ビューの中心を常にシーンの特定の位置(例: (0,0))に合わせる // centerOn(0, 0); // 例3: 古いビューの中心を維持しつつ、新しいビューの中心を計算して移動する(AnchorViewCenterの簡易的な実装) // QPointF oldCenter = mapToScene(event->oldSize().width() / 2, event->oldSize().height() / 2); // QPointF newCenter = mapToScene(event->size().width() / 2, event->size().height() / 2); // QPointF delta = newCenter - oldCenter; // translate(delta.x(), delta.y()); // translate はビューの変換行列を操作する // 例4: マウス位置を基準にズーム(AnchorUnderMouseの簡易的な実装、ただしマウスイベントも必要) // この方法は resizeEvent 単独では難しい。後述の`QEvent::Resize`イベントフィルターの方が適している } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsScene scene; scene.setSceneRect(-400, -300, 800, 600); QGraphicsRectItem *centerRect = new QGraphicsRectItem(-50, -50, 100, 100); centerRect->setBrush(Qt::blue); scene.addItem(centerRect); QGraphicsRectItem *topRightRect = new QGraphicsRectItem(300, -250, 50, 50); topRightRect->setBrush(Qt::red); scene.addItem(topRightRect); MyGraphicsView view(&scene); view.setWindowTitle("Custom Resize Event Example"); view.resize(600, 400); view.show(); return a.exec(); }
-
注意点
QGraphicsView::resizeEvent(event);
を必ず呼び出してください。これを忘れると、スクロールバーの挙動がおかしくなるなど、予期せぬ問題が発生することがあります。fitInView()
をresizeEvent()
内で頻繁に呼び出すと、ビューのリサイズが再帰的にトリガーされ、無限ループに陥る可能性があります。これを避けるためには、フラグを使ったガードや、fitInView
の呼び出しを特定の条件下に限定するなどの対策が必要です。
-
-
イベントフィルターの使用
QObject::installEventFilter()
を使用して、QGraphicsView
オブジェクトのQEvent::Resize
イベントを捕捉する方法です。resizeEvent()
をオーバーライドするのと似ていますが、既存のビュークラスを変更せずにカスタムロジックを追加できる点が異なります。-
用途
- 既存の
QGraphicsView
クラスをサブクラス化せずにリサイズ挙動をカスタマイズしたい場合。 - 複数のビューに共通のリサイズロジックを適用したい場合。
- 既存の
-
実装例
#include <QApplication> #include <QGraphicsView> #include <QGraphicsScene> #include <QGraphicsRectItem> #include <QEvent> #include <QResizeEvent> // イベントフィルターを実装するクラス class ResizeEventFilter : public QObject { Q_OBJECT // Q_OBJECT マクロが必要 public: explicit ResizeEventFilter(QObject *parent = nullptr) : QObject(parent) {} protected: bool eventFilter(QObject *obj, QEvent *event) override { if (event->type() == QEvent::Resize) { QGraphicsView *view = qobject_cast<QGraphicsView*>(obj); if (view) { QResizeEvent *resizeEvent = static_cast<QResizeEvent*>(event); // ここでカスタムリサイズロジックを実装 // 例: シーン全体を常にビューにフィットさせる // QRectF sceneRect = view->scene()->itemsBoundingRect(); // view->fitInView(sceneRect, Qt::KeepAspectRatio); // 例: ビューの中心を常にシーンの中心に合わせる view->centerOn(0, 0); // trueを返すとイベントが消費され、それ以上処理されない // falseを返すとイベントは通常通り処理され続ける(QGraphicsView::resizeEventも呼ばれる) // resizeAnchorのデフォルト挙動を残したい場合はfalseが良いことが多い return false; // または true; } } return QObject::eventFilter(obj, event); // 他のイベントは基底クラスに任せる } }; #include "main.moc" // mocファイルを含める int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsScene scene; scene.setSceneRect(-400, -300, 800, 600); QGraphicsRectItem *centerRect = new QGraphicsRectItem(-50, -50, 100, 100); centerRect->setBrush(Qt::blue); scene.addItem(centerRect); QGraphicsView view(&scene); view.setWindowTitle("Event Filter Resize Example"); view.resize(600, 400); // イベントフィルターをインストール ResizeEventFilter *filter = new ResizeEventFilter(&view); // viewを親に設定 view.installEventFilter(filter); view.show(); return a.exec(); }
-
注意点
eventFilter
からtrue
を返すと、イベントがそこで終了し、QGraphicsView
自身のresizeEvent
は呼び出されません。これは、resizeAnchor
による自動的な挙動を完全に置き換えたい場合に役立ちますが、標準のスクロールバーの更新などが停止する可能性があるので注意が必要です。false
を返すと、イベントはQGraphicsView
のresizeEvent
にも渡され、resizeAnchor
による挙動とカスタムロジックが組み合わさって実行されます。どちらの挙動が必要かによって使い分けます。
-
-
QGraphicsView::setTransform()や関連するメソッドでの手動スケーリング/移動
resizeAnchor
はビューポートの表示領域の調整を自動で行いますが、より細かくズームやパンを制御したい場合は、QGraphicsView::setTransform()
,scale()
,translate()
,rotate()
などのメソッドを直接使用します。-
用途
- 複雑なズームイン/ズームアウトの挙動を実装する場合(例: アニメーションを伴うズーム)。
- ユーザーによる特定のジェスチャー(例: ピンチズーム)に応じたカスタムなビュー操作。
resizeAnchor
とは独立して、特定の条件でビューポートの表示範囲を調整したい場合。
-
実装例(wheelEventでのズームと合わせて)
これはリサイズイベントではありませんが、ビューポートの挙動をカスタマイズする例として関連します。#include <QApplication> #include <QGraphicsView> #include <QGraphicsScene> #include <QGraphicsRectItem> #include <QWheelEvent> // QWheelEvent を使うために必要 class ZoomableGraphicsView : public QGraphicsView { public: ZoomableGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr) : QGraphicsView(scene, parent) { setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); // ズームの中心をマウス位置に setResizeAnchor(QGraphicsView::AnchorViewCenter); // リサイズ時はビューの中心を固定 } 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(); // イベントを処理済みとしてマーク } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsScene scene; scene.setSceneRect(-400, -300, 800, 600); QGraphicsRectItem *rect1 = new QGraphicsRectItem(-100, -100, 200, 200); rect1->setBrush(Qt::cyan); scene.addItem(rect1); ZoomableGraphicsView view(&scene); view.setWindowTitle("Custom Zoom and Resize Example"); view.resize(600, 400); view.centerOn(0,0); view.show(); return a.exec(); }
-
注意点
setTransformationAnchor()
は、scale()
やrotate()
などの変換操作の際にどの点を固定するかを指定します。これはresizeAnchor
とは異なる概念ですが、ズーム挙動をカスタマイズする際には非常に重要です。QGraphicsView::setTransform()
はビューの現在の変換行列を完全に置き換えるため、既存のズームやパンの状態を考慮して新しい行列を計算する必要があります。
-