Qt QGraphicsView: paintEventの基本と描画のベストプラクティス
paintEvent()
とは何か
paintEvent(QPaintEvent *event)
は、Qtのウィジェット(QWidget
を継承するクラス)が自身を描画する際に呼び出されるイベントハンドラです。QGraphicsView
も QWidget
を継承しているため、この paintEvent()
を持っています。
通常、paintEvent()
は以下のような場合にシステムから自動的に呼び出されます。
- ウィジェットのサイズが変更されたとき
- ウィジェットの一部または全体が再描画される必要があるとき(例えば、他のウィンドウに隠されていた部分が表示されるようになった場合や、
update()
またはrepaint()
メソッドが呼び出された場合) - ウィジェットが初めて表示されるとき
QGraphicsView::paintEvent()
の役割
しかし、QGraphicsView
における paintEvent()
の役割は、一般的な QWidget
のそれとは少し異なります。
一般的な QWidget
のサブクラスでは、paintEvent()
をオーバーライドして QPainter
オブジェクトを使い、直接ウィジェット上に図形を描画します。
一方、QGraphicsView
は、その内部に保持している QGraphicsScene
を表示することが主な目的です。そのため、QGraphicsView
の paintEvent()
は、直接描画コードを書く場所としては推奨されません。
QGraphicsView::paintEvent()
のデフォルトの実装は、以下の処理を行います。
- 描画する領域(
event->rect()
またはevent->region()
で指定される更新領域)を特定します。 - その領域に基づいて、
QGraphicsScene
の描画処理をトリガーします。具体的には、QGraphicsScene
に含まれるアイテムのうち、表示されている部分や更新が必要な部分だけが効率的に再描画されるように調整し、QGraphicsItem::paint()
メソッドを呼び出します。 - 必要に応じて、
QGraphicsView
自体の背景やフレームなどの描画も行います。
つまり、QGraphicsView::paintEvent()
は、QGraphicsScene
の描画を管理・調整するための内部的なメカニズムとして機能します。
QGraphicsView
でカスタム描画を行うには?
もし QGraphicsView
上にカスタムな描画を行いたい場合、通常は以下の方法が推奨されます。
-
QGraphicsItem
を継承したカスタムアイテムを作成する: これが最も推奨される方法です。QGraphicsItem
を継承したクラスを作成し、そのpaint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
メソッドをオーバーライドします。このメソッド内でQPainter
を使用して描画を行うことで、Graphics View Frameworkの恩恵(座標変換、衝突検出、アイテムの選択など)を受けられます。作成したアイテムはQGraphicsScene::addItem()
でシーンに追加します。 -
QGraphicsScene
のdrawBackground()
やdrawForeground()
をオーバーライドする: シーン全体の背景や前景に描画したい場合、QGraphicsScene
のサブクラスを作成し、drawBackground()
またはdrawForeground()
メソッドをオーバーライドします。これらのメソッドはQPainter
を引数に取るため、ここでカスタム描画を行うことができます。 -
QGraphicsView
のdrawBackground()
やdrawForeground()
をオーバーライドする(非推奨/特殊なケース):QGraphicsView
自体の背景や前景に描画することも可能ですが、これはビューの座標系で描画されるため、シーンの座標系とは異なります。あまり一般的ではありませんが、ビュー固有の装飾などを描画する際に使用されることがあります。
QGraphicsView::paintEvent()
を直接オーバーライドして QPainter
で描画してしまうと、以下のような問題が発生する可能性があります。
- Graphics View Frameworkの機能喪失: 衝突検出、アイテムのインタラクション(移動、拡大縮小、回転など)、アイテムの選択といったGraphics View Frameworkの便利な機能を活用しにくくなります。
- 座標系の混同:
QGraphicsView
のpaintEvent()
内で描画すると、それはビューの座標系(ピクセル座標)で描画されます。しかし、QGraphicsScene
上のアイテムはシーンの座標系で管理されており、座標変換を手動で管理する必要が生じ、複雑になりがちです。 - 非効率な描画:
QGraphicsView
の持つ効率的な描画最適化(部分的な更新、カリングなど)の恩恵を受けられなくなる可能性があります。
よくあるエラーと問題
-
- 原因:
paintEvent()
をオーバーライドした際に、基底クラスのQGraphicsView::paintEvent(event);
の呼び出しを忘れている。 - 説明:
QGraphicsView
のデフォルトのpaintEvent()
は、内部でQGraphicsScene
の描画をトリガーします。これを呼び出さないと、シーン内のアイテムが描画されません。カスタム描画を行う場合でも、基本的には基底クラスのpaintEvent()
を最初に呼び出すべきです。 - トラブルシューティング: オーバーライドした
paintEvent()
の先頭でQGraphicsView::paintEvent(event);
を呼び出すことを確認してください。
- 原因:
-
パフォーマンスの低下(描画が遅い、カクつく)
-
原因1:
paintEvent()
内で重い処理(ファイルI/O、複雑な計算、非効率なループなど)を行っている。 -
説明:
paintEvent()
は頻繁に呼び出される可能性があるため、ここで時間のかかる処理を行うと、UIの応答性が著しく低下します。 -
トラブルシューティング1:
paintEvent()
内では描画に直接関係する処理のみを行い、他の重い処理は別スレッドやイベントループの外で行うようにリファクタリングします。 -
原因2:
QGraphicsView
の描画最適化(クリッピング、カリング)を妨げている。 -
説明:
QGraphicsView
は、画面に表示されている部分や更新が必要な部分だけを描画するような最適化を自動的に行います。paintEvent()
を不適切にオーバーライドしたり、QGraphicsItem
のboundingRect()
を正しく設定しなかったりすると、この最適化が働かず、不要な部分まで描画されてしまいます。 -
トラブルシューティング2:
QGraphicsItem
を使用している場合、boundingRect()
がそのアイテムの実際の描画領域を正確に返すようにしてください。大きすぎるboundingRect()
は、不要な再描画を引き起こします。QGraphicsItem::paint()
内でQPainter::setClipRect(option->exposedRect)
を使用して、描画領域をクリッピングするのを忘れていないか確認してください。
-
-
QPainter
のエラーメッセージ ("Painter not active", "Widget painting can only begin as a result of a paintEvent.")- 原因:
paintEvent()
の外でQPainter
をQGraphicsView
(または任意のQWidget
) 上で直接使用しようとしている。 - 説明:
QPainter
は、paintEvent()
の内部、またはpaintEvent()
から呼び出された関数内で、かつQPainter
のコンストラクタにQPaintDevice
(通常はthis
またはviewport()
) を渡す形で使用される必要があります。それ以外の場所でQPainter
をアクティブにしようとすると、このエラーが発生します。 - トラブルシューティング:
QGraphicsView
に直接描画したい場合は、必ずpaintEvent()
をオーバーライドし、その中でQPainter painter(this->viewport());
のようにQPainter
を初期化してください。- 理想的には、
QGraphicsItem::paint()
メソッド内で描画を行い、QGraphicsView
上への直接描画は避けるべきです。
- 原因:
-
画面のちらつき(フリッカリング)
- 原因: 描画処理が最適化されていない、またはダブルバッファリングが適切に設定されていない。
- 説明:
paintEvent()
が頻繁に呼び出され、描画のたびに画面がクリアされてから再描画されると、ユーザーにはちらつきとして認識されます。 - トラブルシューティング:
QGraphicsView
はデフォルトでダブルバッファリングを有効にしているはずですが、念のためsetViewportUpdateMode(QGraphicsView::FullViewportUpdate)
やsetViewportUpdateMode(QGraphicsView::SmartViewportUpdate)
の設定を確認してください。通常はSmartViewportUpdate
が推奨されます。- カスタム描画を行っている場合、
QPainter
の描画設定(アンチエイリアシングなど)がパフォーマンスに影響していないか確認します。 QGraphicsScene
やQGraphicsItem
のupdate()
を不必要に頻繁に呼び出していないか確認します。変更があった部分だけをupdate()
するように心がけます(例:update(boundingRect())
)。
-
QGraphicsItem
の描画が期待通りにならない(重なり順、座標変換など)- 原因:
QGraphicsView::paintEvent()
内でQPainter
を使って直接描画している。 - 説明:
QGraphicsView
は、QGraphicsItem
の z-値(重なり順)、座標変換(拡大縮小、回転、移動)、衝突検出などを自動的に処理します。paintEvent()
で直接描画すると、これらのGraphics View Frameworkの恩恵を受けられず、手動で管理する必要が生じ、バグの原因になります。 - トラブルシューティング:
- カスタム描画は必ず
QGraphicsItem
のサブクラスを作成し、そのpaint()
メソッドをオーバーライドして行ってください。 - アイテムの座標は常にシーン座標で考え、ビューの座標系を意識しないようにします。ビューは自動的にシーン座標からビュー座標への変換を行います。
- カスタム描画は必ず
- 原因:
-
paintEvent()
が呼び出されない- 原因: ウィジェットに再描画が必要であるというシグナルが送られていない。
- 説明:
paintEvent()
は、Qtのイベントループによって自動的に呼び出されますが、そのためにはウィジェットが「無効(invalid)」状態になり、再描画が必要であるとマークされる必要があります。 - トラブルシューティング:
- ウィジェットの内容を変更した場合は、必ず
update()
またはrepaint()
メソッドを呼び出してください。update()
: 非同期で、次のイベントループの機会に再描画をスケジュールします。複数のupdate()
呼び出しはマージされ、効率的です。repaint()
: 同期で、即座に再描画を行います。緊急の場合以外はupdate()
が推奨されます。
QGraphicsItem
の位置や見た目を変更した場合は、そのアイテムのupdate()
メソッドを呼び出してください。
- ウィジェットの内容を変更した場合は、必ず
- Qt Forum / Stack Overflow: 多くの開発者が同様の問題に遭遇しています。Qtの公式フォーラムやStack Overflowで検索することで、解決策が見つかることが多いです。
- 最小限の再現コード: 問題が発生した場合、できるだけ最小限のコードでその問題を再現する試みは、原因特定に非常に役立ちます。
- Qt Debugging Toolsの利用: Qt Creatorには、Qt Quick ProfilerなどのGUIパフォーマンスを分析するツールがあります。これらを活用して、描画ボトルネックを特定します。
- デバッグ出力の活用:
paintEvent()
の中や、描画に関わる重要な場所でqDebug()
を使ってメッセージを出力し、いつ、どれくらいの頻度でpaintEvent()
が呼び出されているか、描画にどれくらいの時間がかかっているかなどを確認します。
前述の通り、QGraphicsView::paintEvent()
を直接オーバーライドして描画を行うことは、特殊なケースを除いて推奨されません。その代わりに、Graphics View Frameworkの意図する設計に沿って、QGraphicsItem
や QGraphicsScene
の paint()
メソッドをオーバーライドする方法が一般的です。
QGraphicsItem を継承してカスタム描画を行う (推奨)
これは、Graphics View Frameworkでグラフィカルな要素を描画する最も一般的で推奨される方法です。
MyRectItem.h
#ifndef MYRECTITEM_H
#define MYRECTITEM_H
#include <QGraphicsItem>
#include <QPainter>
class MyRectItem : public QGraphicsItem
{
public:
MyRectItem(const QRectF& rect, QGraphicsItem* parent = nullptr);
// QGraphicsItemを継承する場合、この2つの純粋仮想関数は必須
QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override;
private:
QRectF m_rect;
QColor m_color;
};
#endif // MYRECTITEM_H
MyRectItem.cpp
#include "MyRectItem.h"
#include <QDebug> // デバッグ出力用
MyRectItem::MyRectItem(const QRectF& rect, QGraphicsItem* parent)
: QGraphicsItem(parent),
m_rect(rect),
m_color(Qt::blue) // デフォルトの色
{
// アイテムがクリック可能であることを示すフラグ
setFlag(ItemIsSelectable);
setFlag(ItemIsMovable);
}
QRectF MyRectItem::boundingRect() const
{
// アイテムの描画領域を正確に返す。
// これが不正確だと、描画のちらつきや不要な再描画の原因になる。
return m_rect;
}
void MyRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
Q_UNUSED(widget); // この例では使用しない
// デバッグ出力 (描画が呼ばれていることを確認)
qDebug() << "Painting MyRectItem at" << m_rect;
// クリッピング設定: 描画領域をoption->exposedRectに制限することで、
// 不要な描画を避けてパフォーマンスを向上させる。
painter->setClipRect(option->exposedRect);
// 選択されている場合は色を変える
if (option->state & QStyle::State_Selected) {
painter->setBrush(QBrush(m_color.darker(150))); // 暗くする
} else {
painter->setBrush(QBrush(m_color));
}
// 枠線の設定
painter->setPen(QPen(Qt::black, 2));
// 長方形を描画
painter->drawRect(m_rect);
// テキストを描画 (シーン座標)
painter->setPen(Qt::white);
painter->drawText(m_rect, Qt::AlignCenter, "Hello Qt!");
}
使用例 (main.cpp
または MainWindow
クラス)
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include "MyRectItem.h" // 作成したカスタムアイテム
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// シーンを作成
QGraphicsScene scene;
scene.setSceneRect(0, 0, 800, 600); // シーンの論理的なサイズ
// カスタムアイテムをいくつか作成してシーンに追加
MyRectItem* rect1 = new MyRectItem(QRectF(50, 50, 100, 100));
rect1->setPos(0, 0); // シーン上の位置
scene.addItem(rect1);
MyRectItem* rect2 = new MyRectItem(QRectF(0, 0, 80, 120));
rect2->setPos(200, 100);
scene.addItem(rect2);
// ビューを作成し、シーンを設定
QGraphicsView view(&scene);
view.setRenderHint(QPainter::Antialiasing); // アンチエイリアシングを有効にする
view.setWindowTitle("Custom QGraphicsItem Example");
view.resize(820, 620); // ビューのウィンドウサイズ
view.show();
return a.exec();
}
解説:
QGraphicsView
は単にQGraphicsScene
を表示する役割を担います。アイテムの描画はビューではなく、アイテム自身が行います。option->exposedRect
を使用してQPainter::setClipRect()
を設定することで、実際に更新が必要な領域のみを描画し、描画パフォーマンスを向上させています。paint()
メソッド内でQPainter
を使用して実際の描画を行います。ここで描画される座標は、アイテムのローカル座標系です。boundingRect()
は、そのアイテムが占める最小の矩形領域を返します。Qtはこの情報を使って、描画の最適化(どのアイテムを描画する必要があるか)を行います。正確なboundingRect()
はパフォーマンスに非常に重要です。MyRectItem
はQGraphicsItem
を継承し、boundingRect()
とpaint()
をオーバーライドしています。
シーン全体の背景や前景に描画したい場合に使用します。グリッド線や背景画像など、シーン全体に関わる描画に適しています。
MyGraphicsScene.h
#ifndef MYGRAPHICSSCENE_H
#define MYGRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QPainter>
class MyGraphicsScene : public QGraphicsScene
{
public:
MyGraphicsScene(QObject* parent = nullptr);
protected:
void drawBackground(QPainter* painter, const QRectF& rect) override;
void drawForeground(QPainter* painter, const QRectF& rect) override;
};
#endif // MYGRAPHICSSCENE_H
MyGraphicsScene.cpp
#include "MyGraphicsScene.h"
#include <QDebug>
MyGraphicsScene::MyGraphicsScene(QObject* parent)
: QGraphicsScene(parent)
{
}
void MyGraphicsScene::drawBackground(QPainter* painter, const QRectF& rect)
{
Q_UNUSED(rect); // この例ではrect全体に描画
// デバッグ出力
qDebug() << "Drawing scene background";
// シーンの背景色を設定
painter->fillRect(sceneRect(), Qt::lightGray);
// グリッド線を描画 (シーン座標)
qreal gridSize = 20;
QPen gridPen(Qt::darkGray, 0.5);
painter->setPen(gridPen);
for (qreal x = sceneRect().left(); x < sceneRect().right(); x += gridSize) {
painter->drawLine(QPointF(x, sceneRect().top()), QPointF(x, sceneRect().bottom()));
}
for (qreal y = sceneRect().top(); y < sceneRect().bottom(); y += gridSize) {
painter->drawLine(QPointF(sceneRect().left(), y), QPointF(sceneRect().right(), y));
}
}
void MyGraphicsScene::drawForeground(QPainter* painter, const QRectF& rect)
{
Q_UNUSED(rect);
// デバッグ出力
qDebug() << "Drawing scene foreground";
// シーンの四隅にテキストを描画 (シーン座標)
painter->setPen(QPen(Qt::red, 2));
painter->setFont(QFont("Arial", 16));
painter->drawText(sceneRect().topLeft() + QPointF(10, 20), "Top-Left");
painter->drawText(sceneRect().topRight() + QPointF(-80, 20), "Top-Right");
painter->drawText(sceneRect().bottomLeft() + QPointF(10, -10), "Bottom-Left");
painter->drawText(sceneRect().bottomRight() + QPointF(-100, -10), "Bottom-Right");
}
使用例 (main.cpp
または MainWindow
クラス)
#include <QApplication>
#include <QGraphicsView>
#include "MyGraphicsScene.h" // 作成したカスタムシーン
#include "MyRectItem.h" // 必要であればカスタムアイテムも追加
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// カスタムシーンを作成
MyGraphicsScene* scene = new MyGraphicsScene();
scene->setSceneRect(0, 0, 800, 600); // シーンの論理的なサイズ
// (オプション) カスタムアイテムをシーンに追加
MyRectItem* rect = new MyRectItem(QRectF(150, 150, 200, 100));
scene->addItem(rect);
// ビューを作成し、シーンを設定
QGraphicsView view(scene);
view.setRenderHint(QPainter::Antialiasing);
view.setWindowTitle("Custom QGraphicsScene Background/Foreground");
view.resize(820, 620);
view.show();
return a.exec();
}
解説:
- 描画は常にシーン座標系で行われます。
- これらのメソッドは、ビューに表示されているシーンの部分を示す
rect
引数を受け取ります。このrect
を利用して、必要な部分だけを描画することでパフォーマンスを最適化できます。 MyGraphicsScene
はQGraphicsScene
を継承し、drawBackground()
とdrawForeground()
をオーバーライドしています。
この方法は、ビューポート(QGraphicsView
の表示領域)に直接、シーンとは独立した描画を行いたい場合に限定されます。例えば、ビューの上にデバッグ情報や特別なUI要素をオーバーレイ表示するような場合です。しかし、ほとんどのケースでは QGraphicsItem
や QGraphicsScene
を使うべきです。
MyGraphicsView.h
#ifndef MYGRAPHICSVIEW_H
#define MYGRAPHICSVIEW_H
#include <QGraphicsView>
#include <QPainter>
#include <QPaintEvent>
class MyGraphicsView : public QGraphicsView
{
Q_OBJECT // QObjectを継承しているのでQ_OBJECTマクロが必要
public:
MyGraphicsView(QGraphicsScene* scene, QWidget* parent = nullptr);
protected:
// paintEventをオーバーライド
void paintEvent(QPaintEvent* event) override;
};
#endif // MYGRAPHICSVIEW_H
MyGraphicsView.cpp
#include "MyGraphicsView.h"
#include <QDebug>
MyGraphicsView::MyGraphicsView(QGraphicsScene* scene, QWidget* parent)
: QGraphicsView(scene, parent)
{
}
void MyGraphicsView::paintEvent(QPaintEvent* event)
{
// !!! 重要: 基底クラスのpaintEventを必ず呼び出す !!!
// これを忘れると、QGraphicsSceneのアイテムが描画されません。
QGraphicsView::paintEvent(event);
// ここからがMyGraphicsView独自の描画
// QPainterはviewport()に対して描画する
QPainter painter(this->viewport());
// デバッグ出力 (このpaintEventが呼ばれていることを確認)
qDebug() << "Custom MyGraphicsView::paintEvent called.";
// ビューポートの中央に赤い円を描画 (ビューポート座標)
painter.setPen(QPen(Qt::red, 3));
painter.setBrush(Qt::NoBrush);
painter.drawEllipse(rect().center(), 50, 50); // ビューの中心に半径50の円
// ビューポートの右下隅にテキストを描画 (ビューポート座標)
painter.setPen(Qt::darkGreen);
painter.setFont(QFont("Consolas", 14));
painter.drawText(rect().bottomRight() - QPoint(150, 30), "View Overlay Text");
// 更新が必要な領域に描画を制限することも可能
// painter.setClipRect(event->rect());
// (QGraphicsView::paintEventが既に適切なクリッピングを設定しているため、
// ここで再度設定する必要はないことが多いですが、理解のために記述)
}
使用例 (main.cpp
または MainWindow
クラス)
#include <QApplication>
#include <QGraphicsScene>
#include "MyGraphicsView.h" // 作成したカスタムビュー
#include "MyRectItem.h" // 必要であればカスタムアイテムも追加
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(0, 0, 800, 600);
// アイテムをシーンに追加
MyRectItem* rect = new MyRectItem(QRectF(100, 100, 150, 150));
scene.addItem(rect);
// カスタムビューを作成し、シーンを設定
MyGraphicsView view(&scene);
view.setRenderHint(QPainter::Antialiasing);
view.setWindowTitle("Custom QGraphicsView::paintEvent Example");
view.resize(820, 620);
view.show();
return a.exec();
}
解説:
- ここで描画される座標はビューポートのピクセル座標(
QGraphicsView
ウィジェットの左上隅が (0,0))です。シーンの座標系とは異なりますので注意が必要です。 - その後の描画は、
QGraphicsView
のビューポート(表示されている実際のピクセル領域)に対して行われます。したがって、QPainter(this->viewport())
のようにQPainter
を初期化します。 - 最も重要なのは、
QGraphicsView::paintEvent(event);
を必ず最初に呼び出すことです。 これにより、シーンのアイテムが通常通り描画されます。 MyGraphicsView
はQGraphicsView
を継承し、paintEvent()
をオーバーライドしています。
主な代替方法は以下の3つです。
QGraphicsItem::paint() をオーバーライドする (最も推奨)
これは、QGraphicsView
上に表示される具体的なグラフィック要素を作成するための最も推奨される方法です。あらゆる形状、画像、テキスト、カスタムウィジェットなどを表現できます。
- 注意点:
boundingRect()
を正確に実装することがパフォーマンス上非常に重要です。 - 用途:
- カスタムな図形(多角形、曲線など)
- 特定の画像やテキストの配置
- ユーザーインタラクションが必要な要素(ボタン、スライダーの視覚化など)
- グラフのノードやエッジ
- 利点:
- シーン座標系での描画: アイテムはシーンの論理的な座標系で描画されるため、
QGraphicsView
のズームや回転といった変換を自動的に引き継ぎます。 - 描画の最適化:
QGraphicsItem
は自身の描画領域 (boundingRect()
) をQtに伝えることで、表示されている部分だけを描画する「カリング」や「部分更新」といった最適化が自動的に適用されます。 - インタラクション: 移動、回転、拡大縮小、選択、衝突検出など、
QGraphicsItem
が提供する豊富な機能やイベントハンドラ (mousePressEvent()
,hoverEnterEvent()
など) を利用できます。 - 階層構造: アイテムを親子関係にすることで、複雑なグラフィックを整理し、親アイテムの変換が子アイテムに自動的に適用される階層構造を作成できます。
- シーン座標系での描画: アイテムはシーンの論理的な座標系で描画されるため、
QGraphicsScene::drawBackground() / QGraphicsScene::drawForeground() をオーバーライドする
シーン全体の背景や前景に描画したい場合に利用します。アイテムとは独立した、シーン全体にわたる描画に適しています。
- 注意点: これらのメソッド内で、シーン内の個々のアイテムの状態に基づいて複雑な描画を行うのは避けるべきです。アイテム固有の描画は
QGraphicsItem::paint()
で行うべきです。 - 用途:
- カスタムのグリッド線
- シーン全体の背景画像やグラデーション
- シーンの寸法ガイドや枠線
- デバッグ用のオーバーレイ情報(例: シーンの座標軸)
- 利点:
- シーン座標系での描画:
QGraphicsItem
と同様に、シーンの論理的な座標系で描画されるため、ビューの変換に自動的に対応します。 - 効率的な描画:
rect
引数によって、ビューに表示されている、あるいは更新が必要なシーンの領域のみを描画できます。 - シーン全体の装飾: シーン全体のグリッド線、背景画像、透かし、デバッグ情報などを描画するのに適しています。
- シーン座標系での描画:
より高度な描画制御が必要な場合や、特定のQGraphicsView
インスタンスに依存する描画を行いたい場合に検討されます。
代替方法 | 描画座標系 | 主な用途 | 特徴 |
---|---|---|---|
QGraphicsItem::paint() | シーン座標 | 個々のグラフィック要素、インタラクティブなオブジェクト | 最も推奨。自動的な変換、最適化、インタラクション機能。 boundingRect() が重要。 |
QGraphicsScene::drawBackground() / drawForeground() | シーン座標 | シーン全体の背景/前景、グリッド線など | シーン全体にわたる装飾。ビューの変換に追従。 |
QGraphicsView::drawBackground() / drawForeground() | ビューポート座標 | ビュー固有のオーバーレイ、装飾 | ビューのピクセル座標で描画。シーンの変換とは独立。 |
カスタム QWidget をビューポートとして設定 | ビューポート座標 | QWidget の描画機能を活用したい場合 | 低レベル。特殊なケース。 |
QGraphicsView の上に別の QWidget を重ねる | ウィジェット固有 | UI要素の配置、コントロール | 完全に独立したUIレイヤー。 |