QGraphicsItem::update() vs QGraphicsScene::update() vs QGraphicsView::updateScene()徹底比較

2025-05-27

void QGraphicsView::updateScene() とは何か

QGraphicsView::updateScene() は、QtのGraphics View Frameworkにおいて、ビュー(QGraphicsView)が表示しているシーン(QGraphicsScene)の変更をビューに通知し、再描画をスケジュールするための関数です。

より具体的に言うと、この関数は、QGraphicsView が自身の描画領域(ビューポート)のうち、引数で指定された矩形領域に対応するシーンの領域を再描画する必要があることを示します。

どのようなときに使うのか

通常、QGraphicsScene 内のアイテム(QGraphicsItem)が移動したり、サイズが変更されたり、表示/非表示が切り替わったりすると、自動的にシーンの変更が通知され、関連するビューが再描画されます。

しかし、以下のような場合には、明示的に updateScene() を呼び出す必要があることがあります。

  1. カスタムな描画ロジック: QGraphicsItempaint() メソッドをオーバーライドして、独自の描画を行っている場合、その描画内容が変更されたときに、Qtが自動的に変更を検知できないことがあります。
  2. シーンの背景や前景の描画変更: QGraphicsScene の背景や前景の描画を drawBackground()drawForeground() をオーバーライドして変更した場合、その変更をビューに反映させるために updateScene() を呼び出すことがあります。
  3. パフォーマンスの最適化: 複数のアイテムが頻繁に更新される場合など、特定の領域のみを効率的に再描画したいときに、updateScene(const QList<QRectF> &rects) のオーバーロードを使って、更新が必要な領域を明示的に指定することで、描画処理の負荷を軽減できます。

オーバーロード

updateScene() には、いくつかのオーバーロードがあります。

  • void QGraphicsView::updateScene(const QList<QRectF> &rects): このオーバーロードは、rects で指定された複数の矩形領域に対応するシーンの領域のみを再描画するようにスケジュールします。これにより、変更があった部分だけを効率的に更新できるため、パフォーマンスが向上する可能性があります。

  • void QGraphicsView::updateScene(): 引数なしのこの関数は、現在表示されているビューポート全体を再描画するようにスケジュールします。これは通常、シーン全体に変更があった場合や、単純にビューポート全体をリフレッシュしたい場合に便利です。

  • QGraphicsView::viewportUpdateMode プロパティを設定することで、ビューがどのように再描画を処理するかを制御できます。例えば、MinimalViewportUpdate(デフォルト)は最小限の領域を再描画し、FullViewportUpdate は常にビューポート全体を再描画します。
  • 多くの場合、QGraphicsScene のアイテムの変更は自動的にビューに反映されるため、updateScene() を明示的に呼び出す必要がないこともあります。しかし、意図したように描画が更新されない場合に、この関数を検討すると良いでしょう。
  • updateScene() は、直接描画を行うのではなく、再描画をスケジュールします。実際の描画は、Qtのイベントループ内で適切なタイミングで行われます。


QGraphicsView::updateScene() は、Qt の Graphics View Framework においてビューの再描画を制御するための重要な関数ですが、使い方を誤ると意図しない表示になったり、パフォーマンスの問題を引き起こしたりすることがあります。

エラー/問題: 変更がビューに反映されない (最も一般的なケース)

症状
QGraphicsItem のプロパティ(位置、サイズ、色など)を変更したり、QGraphicsScene の背景/前景の描画を更新したりしても、QGraphicsView にその変更が表示されない。

原因

  • QGraphicsView::viewportUpdateMode の設定
    QGraphicsView::viewportUpdateModeNoViewportUpdate に設定されている場合、ビューは一切再描画されません。
  • シーンの背景/前景の変更
    QGraphicsScene::drawBackground()QGraphicsScene::drawForeground() をオーバーライドして描画している場合、その描画内容が変更されても自動的には更新されません。
  • カスタム描画の通知不足
    QGraphicsItempaint() メソッドをオーバーライドしてカスタムな描画を行っている場合、その描画ロジック内で使われているデータが変更されても、Qt はその変更を自動的に検知できません。
  • 自動更新の不理解
    QGraphicsItem の基本的なプロパティ変更(例: setPos(), setSize(), setVisible(), setBrush() など)は、通常、アイテム自身が変更通知を発行し、QGraphicsScene を介して関連する QGraphicsView に自動的に再描画がスケジュールされます。updateScene() を明示的に呼び出す必要がないケースが多いです。

トラブルシューティング

  1. QGraphicsItem::update() を使う
    QGraphicsItem のカスタム描画内容が変更された場合は、そのアイテムの update() メソッドを呼び出してください。これは、特定のアイテムの再描画をスケジュールする最も推奨される方法です。
    myGraphicsItem->update(); // アイテム全体を再描画
    // または
    myGraphicsItem->update(QRectF(x, y, width, height)); // アイテム内の特定の領域を再描画
    
  2. QGraphicsScene::update() を使う
    シーンの背景や前景の描画内容が変更された場合、またはシーン全体に影響する変更があった場合は、QGraphicsScene::update() を呼び出してください。これは、QGraphicsScene 全体(または指定した領域)の再描画をスケジュールします。
    myGraphicsScene->update(); // シーン全体を再描画
    // または
    myGraphicsScene->update(QRectF(x, y, width, height)); // シーン内の特定の領域を再描画
    
  3. updateScene() の適切な使用
    QGraphicsView::updateScene() は、QGraphicsScene 側で更新が行われたにもかかわらず、何らかの理由で QGraphicsView がその更新を認識しない場合に、QGraphicsView に対して明示的にシーンの再描画を促すために使います。通常は、QGraphicsItem::update()QGraphicsScene::update() で十分です。
    myGraphicsView->updateScene(); // 現在のビューポート全体を再描画
    // または
    myGraphicsView->updateScene(QList<QRectF>() << QRectF(x, y, width, height)); // シーンの特定の領域を再描画
    
  4. QGraphicsView::viewportUpdateMode の確認
    // 現在の更新モードを確認
    qDebug() << myGraphicsView->viewportUpdateMode();
    // 必要に応じて設定を変更
    myGraphicsView->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); // デフォルトで推奨
    

エラー/問題: パフォーマンスの問題 (描画が遅い、ちらつく)

症状
QGraphicsView の描画が非常に遅い、または画面が頻繁にちらつく。

原因

  • QGraphicsView::FullViewportUpdate モード
    viewportUpdateModeFullViewportUpdate に設定されている場合、常にビューポート全体が再描画されるため、パフォーマンスに影響を与えます。
  • updateScene() (引数なし) の過度な使用
    わずかな変更しかないのに、引数なしの updateScene() を呼び出すと、ビューポート全体が常に再描画され、非効率です。
  • 不必要な updateScene() の頻繁な呼び出し
    変更がないのに何度も updateScene() を呼び出すと、描画が頻繁に行われ、CPUリソースを無駄に消費します。

トラブルシューティング

  1. 変更があった領域のみを更新
    • QGraphicsItem のカスタム描画の場合は、QGraphicsItem::update(const QRectF &rect) を使って、変更があったアイテム内の特定の領域のみを更新する。
    • QGraphicsScene のカスタム描画の場合は、QGraphicsScene::update(const QRectF &rect) を使って、変更があったシーンの特定の領域のみを更新する。
    • QGraphicsView::updateScene(const QList<QRectF> &rects) を使用して、ビューに対して更新が必要なシーンの領域を明示的に伝える。
  2. 不必要な呼び出しを避ける
    変更が発生したときにのみ、update() または updateScene() を呼び出すようにロジックを修正する。タイマーなどを使って定期的に更新するのではなく、変更があったことを示すシグナル/スロットやイベントハンドラ内で呼び出すようにする。
  3. QGraphicsView::MinimalViewportUpdate の使用
    デフォルトの MinimalViewportUpdate モードが最も効率的です。特殊な理由がない限り、このモードを使用してください。
    myGraphicsView->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
    
  4. アイテムの最適化
    • QGraphicsItem::setCacheMode(QGraphicsItem::DeviceCoordinateCache) を使用して、複雑なアイテムの描画結果をキャッシュする。ただし、アイテムが頻繁に変化する場合は、この設定が逆効果になることもあります。
    • 多くの小さなアイテムがある場合は、それらをグループ化する(QGraphicsItemGroup を使用するなど)ことで、描画オーバーヘッドを削減できることがあります。

エラー/問題: 描画順序の問題

症状
アイテムの重なり順や描画の前後関係が意図した通りにならない。

原因
updateScene() 自体が直接描画順序を制御するわけではありませんが、再描画のタイミングによっては、更新が完了する前に別の描画が開始され、視覚的に問題が発生する可能性があります。

トラブルシューティング

  1. QGraphicsItem::stackingOrder / setZValue()
    アイテムの描画順序は、QGraphicsItem::setZValue() で設定する Z値によって決定されます。Z値が高いアイテムほど手前に描画されます。
  2. 描画キャッシュの確認
    QGraphicsItem::setCacheMode() を使用している場合、キャッシュされた描画が古い情報を含んでいる可能性があります。変更後には適切にキャッシュを無効化するか、update() を呼び出して再キャッシュを促す必要があります。

updateScene() は、QGraphicsView の再描画をスケジュールするための強力なツールですが、ほとんどのケースでは QGraphicsItem::update()QGraphicsScene::update() で十分です。

  • 変更が発生したときのみ更新をスケジュールする
  • 変更があった領域のみを更新する


先に述べたように、QGraphicsView::updateScene()は、QGraphicsViewがQGraphicsSceneの変更を検知し、再描画をスケジュールするために使用されます。しかし、ほとんどのQGraphicsItemの変更は自動的に処理されるため、この関数を直接呼び出すことは稀です。通常は、QGraphicsItem::update()QGraphicsScene::update() を使用する方が適切です。

ここでは、それぞれのupdate系の関数の使用例と、QGraphicsView::updateScene()が役立つ可能性のある状況を示します。

例1: QGraphicsItemのカスタム描画の更新 (推奨される方法)

この例では、カスタムの QGraphicsRectItem を作成し、その内部の状態(色)が変更されたときに、QGraphicsItem::update() を呼び出して再描画を促します。これが最も一般的な更新方法です。

myrectitem.h

#ifndef MYRECTITEM_H
#define MYRECTITEM_H

#include <QGraphicsRectItem>
#include <QBrush>
#include <QObject> // Q_OBJECT マクロを使用するために必要

class MyRectItem : public QObject, public QGraphicsRectItem
{
    Q_OBJECT // シグナル/スロットを使用する場合に必要
public:
    MyRectItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent = nullptr);

    void setColor(const QColor &color);

private:
    QBrush currentBrush;

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
};

#endif // MYRECTITEM_H

myrectitem.cpp

#include "myrectitem.h"
#include <QPainter>
#include <QDebug>

MyRectItem::MyRectItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent)
    : QGraphicsRectItem(x, y, width, height, parent)
{
    currentBrush = Qt::red; // 初期色
    setBrush(currentBrush); // 基本的なブラシを設定
}

void MyRectItem::setColor(const QColor &color)
{
    if (currentBrush.color() != color) {
        currentBrush.setColor(color);
        // アイテムの描画内容が変更されたことをQtに通知
        // これにより、関連するQGraphicsViewが自動的に再描画をスケジュールします
        update(); // QGraphicsItem::update() を使用
        qDebug() << "Item color changed to" << color.name();
    }
}

void MyRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);

    // カスタム描画ロジック
    painter->setBrush(currentBrush);
    painter->drawRect(rect());
}

main.cpp

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QTimer>
#include "myrectitem.h"

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

    QGraphicsScene scene;
    MyRectItem *rectItem = new MyRectItem(0, 0, 100, 100);
    scene.addItem(rectItem);

    QGraphicsView view(&scene);
    view.setRenderHint(QPainter::Antialiasing); // アンチエイリアスを有効に
    view.setMinimumSize(400, 300);
    view.show();

    // アイテムの色を定期的に変更するタイマー
    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&]() {
        static int colorIndex = 0;
        QColor colors[] = {Qt::red, Qt::green, Qt::blue, Qt::yellow};
        rectItem->setColor(colors[colorIndex % 4]);
        colorIndex++;
    });
    timer.start(1000); // 1秒ごとに色を変更

    return a.exec();
}

解説
この例では、MyRectItem::setColor() 内で update() を呼び出しています。これにより、QtはMyRectItemが描画されるべき領域を無効化し、次回イベントループがアイドル状態になったときに再描画をスケジュールします。QGraphicsView::updateScene()を明示的に呼び出す必要はありません。

例2: QGraphicsSceneの背景/前景の更新

QGraphicsSceneの背景や前景をカスタムで描画している場合、その描画内容が変更されたときにQGraphicsScene::update()を呼び出す必要があります。

myscene.h

#ifndef MYSCENE_H
#define MYSCENE_H

#include <QGraphicsScene>
#include <QColor>

class MyScene : public QGraphicsScene
{
    Q_OBJECT
public:
    MyScene(QObject *parent = nullptr);

    void setBackgroundColor(const QColor &color);

protected:
    void drawBackground(QPainter *painter, const QRectF &rect) override;

private:
    QColor backgroundColor;
};

#endif // MYSCENE_H

myscene.cpp

#include "myscene.h"
#include <QPainter>
#include <QDebug>

MyScene::MyScene(QObject *parent)
    : QGraphicsScene(parent)
{
    backgroundColor = Qt::lightGray; // 初期背景色
}

void MyScene::setBackgroundColor(const QColor &color)
{
    if (backgroundColor != color) {
        backgroundColor = color;
        // シーンの背景が変更されたことをQtに通知
        update(); // QGraphicsScene::update() を使用
        qDebug() << "Scene background color changed to" << color.name();
    }
}

void MyScene::drawBackground(QPainter *painter, const QRectF &rect)
{
    Q_UNUSED(rect); // 描画する矩形領域

    painter->fillRect(sceneRect(), backgroundColor); // シーン全体を背景色で塗りつぶす
    // ここにさらにカスタム描画ロジックを追加できます
}

main.cpp

#include <QApplication>
#include <QGraphicsView>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QTimer>
#include "myscene.h"

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

    MyScene scene;
    scene.setSceneRect(-200, -150, 400, 300); // シーンの範囲を設定

    QGraphicsView view(&scene);
    view.setRenderHint(QPainter::Antialiasing);
    view.setMinimumSize(400, 300);
    view.show();

    // シーンの背景色を定期的に変更するタイマー
    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&]() {
        static int colorIndex = 0;
        QColor colors[] = {Qt::lightGray, Qt::darkGray, Qt::cyan, Qt::magenta};
        scene.setBackgroundColor(colors[colorIndex % 4]);
        colorIndex++;
    });
    timer.start(1500); // 1.5秒ごとに背景色を変更

    return a.exec();
}

解説
MyScene::setBackgroundColor()内でupdate()を呼び出すことで、シーン全体(またはupdate(QRectF)で指定した領域)の再描画がスケジュールされます。ここでもQGraphicsView::updateScene()を直接呼び出す必要はありません。

QGraphicsView::updateScene()は、通常、QGraphicsItem::update()QGraphicsScene::update()で事足りるため、あまり直接呼び出すことはありません。しかし、ビュー側から、シーンの特定の部分の再描画を強制したいが、その変更がアイテムやシーンのプロパティ変更によるものではないような、より複雑なシナリオでは役立つ可能性があります。

例えば、複数のQGraphicsViewが同じQGraphicsSceneを表示していて、そのうちの特定のビューだけが、シーン内の何らかの非標準的な変更を特別な方法で表示する必要がある場合などです。

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QPushButton>
#include <QVBoxLayout>
#include <QTimer>
#include <QDebug>

class MyCustomView : public QGraphicsView
{
    Q_OBJECT
public:
    MyCustomView(QGraphicsScene *scene, QWidget *parent = nullptr)
        : QGraphicsView(scene, parent)
    {
        // ビューポートの更新モードをMinimalViewportUpdateに設定(デフォルト)
        // setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
    }

public slots:
    void forcePartialSceneUpdate()
    {
        // シーン内の特定の領域 (0,0)から(50,50) の矩形を強制的に更新
        // 通常はQGraphicsItem::update()やQGraphicsScene::update()で十分ですが、
        // ビュー側から明示的にシーンの特定の領域を更新したい場合に使う
        QRectF rectToUpdate(0, 0, 50, 50);
        QList<QRectF> rects;
        rects << rectToUpdate;
        updateScene(rects);
        qDebug() << "QGraphicsView::updateScene() called for" << rectToUpdate;
    }

    void forceFullSceneUpdate()
    {
        // シーン全体を強制的に更新
        updateScene();
        qDebug() << "QGraphicsView::updateScene() called for full scene.";
    }
};

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

    QGraphicsScene scene;
    QGraphicsRectItem *rect1 = scene.addRect(0, 0, 100, 100, QPen(Qt::black), QBrush(Qt::cyan));
    rect1->setPos(-50, -50); // シーンの中心に配置

    QGraphicsRectItem *rect2 = scene.addRect(0, 0, 50, 50, QPen(Qt::black), QBrush(Qt::magenta));
    rect2->setPos(70, 70);

    MyCustomView view(&scene);
    view.setRenderHint(QPainter::Antialiasing);
    view.setMinimumSize(400, 300);
    view.show();

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);
    layout->addWidget(&view);

    QPushButton *partialUpdateButton = new QPushButton("Force Partial Scene Update (0,0,50,50)");
    QObject::connect(partialUpdateButton, &QPushButton::clicked, &view, &MyCustomView::forcePartialSceneUpdate);
    layout->addWidget(partialUpdateButton);

    QPushButton *fullUpdateButton = new QPushButton("Force Full Scene Update");
    QObject::connect(fullUpdateButton, &QPushButton::clicked, &view, &MyCustomView::forceFullSceneUpdate);
    layout->addWidget(fullUpdateButton);

    window.setWindowTitle("QGraphicsView::updateScene() Example");
    window.show();

    return a.exec();
}

#include "main.moc" // Q_OBJECT を使用しているため必要

解説
この例では、MyCustomViewというQGraphicsViewのサブクラスを作成し、ボタンクリックに応じてforcePartialSceneUpdate()forceFullSceneUpdate()を呼び出しています。

  • forceFullSceneUpdate(): updateScene() (引数なし) を使用して、ビューポート全体を再描画するように指示しています。これは、ビュー全体のリフレッシュが必要な場合に便利ですが、パフォーマンスに影響を与える可能性があります。
  • forcePartialSceneUpdate(): updateScene(const QList<QRectF> &rects) を使用して、シーンの特定の矩形領域のみを更新するように指示しています。この場合、(0,0)から(50,50)の領域が更新対象となります。これは、その領域が変更されたが、アイテムのプロパティ変更による自動更新がトリガーされない場合に役立ちます。

重要な注意点
上記のQGraphicsView::updateScene()を使用する例は、アイテムのプロパティ変更やシーンの背景/前景の描画変更が自動的にビューに反映されない、特定のニッチな状況で考慮されるべきです。ほとんどの場合、QGraphicsItem::update()QGraphicsScene::update()が適切な解決策であり、より効率的です。



void QGraphicsView::updateScene() の代替方法

以前の説明でも触れたように、QGraphicsView::updateScene() は、特定のニッチな状況を除いて、Qt Graphics View Frameworkにおける描画更新の主要なメカニズムではありません。ほとんどの場合、より具体的で効率的な代替手段が存在します。

主な代替方法は以下の2つです。

  1. QGraphicsItem::update()
  2. QGraphicsScene::update()

これらは、それぞれアイテムレベル、またはシーンレベルでの更新を管理するための推奨される方法です。

QGraphicsItem::update()

用途
個々のQGraphicsItem(例えば、矩形、円、テキスト、カスタム描画アイテムなど)の描画内容が変更された場合に、そのアイテム自身、またはその一部のみを再描画する必要があるときに使用します。

仕組み
QGraphicsItem::update() を呼び出すと、Qtは、そのアイテムが描画されるべき領域を無効化し、関連するQGraphicsSceneに対してその領域の再描画を要求します。QGraphicsSceneは、その更新要求を処理し、それに関連するQGraphicsViewに再描画をスケジュールします。

利点

  • 自動的な伝播
    QGraphicsItemからQGraphicsSceneQGraphicsViewへと更新要求が自動的に伝播します。
  • 粒度が高い
    アイテムの特定の部分のみを更新することも可能です。
  • 最も効率的
    変更があったアイテムの領域のみを再描画するため、不要な描画を避けてパフォーマンスを最適化します。

使用例

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QTimer>
#include <QDebug>

class MyChangingRect : public QGraphicsRectItem
{
public:
    MyChangingRect(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent = nullptr)
        : QGraphicsRectItem(x, y, width, height, parent)
    {
        setBrush(Qt::blue); // 初期色
    }

    void changeColor()
    {
        // 色をランダムに変更
        QColor newColor(QColor::fromRgb(qrand() % 256, qrand() % 256, qrand() % 256));
        if (brush().color() != newColor) {
            setBrush(newColor); // QtはsetBrush()によって自動的に更新をトリガーすることが多いですが、
                               // カスタム描画内容が変更された場合は明示的にupdate()を呼び出します。
            // アイテムの描画内容が変更されたことをQtに通知
            update(); // アイテム全体を再描画
            qDebug() << "Item color changed and updated: " << newColor.name();
        }
    }

    // 特定の領域のみを更新する例
    void updatePartial() {
        // アイテムの左半分のみを更新
        update(rect().adjusted(0, 0, -rect().width() / 2, 0));
        qDebug() << "Partial update of item.";
    }
};

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

    QGraphicsScene scene;
    MyChangingRect *rectItem = new MyChangingRect(0, 0, 100, 100);
    scene.addItem(rectItem);

    QGraphicsView view(&scene);
    view.setRenderHint(QPainter::Antialiasing);
    view.setWindowTitle("QGraphicsItem::update() Example");
    view.show();

    // 1秒ごとにアイテムの色を変更し、update()を呼び出す
    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, rectItem, &MyChangingRect::changeColor);
    timer.start(1000);

    return a.exec();
}

QGraphicsScene::update()

用途
QGraphicsScene背景や前景の描画内容が変更された場合、またはシーン全体に影響する変更(例えば、カスタムなグリッド描画が変更された場合など)があり、それらをすべてのビューに反映させたいときに使用します。

仕組み
QGraphicsScene::update() を呼び出すと、シーンの指定された領域が無効化され、そのシーンを表示しているすべてのQGraphicsViewに対して、その領域の再描画がスケジュールされます。

利点

  • シーンレベルの更新
    シーン全体の背景や前景など、アイテムに属さない描画の変更に対応できます。
  • 複数のビューに適用
    同じシーンを表示している複数のビューすべてに更新を通知できます。

使用例

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QPainter>
#include <QTimer>
#include <QDebug>

class MyCustomScene : public QGraphicsScene
{
    Q_OBJECT
public:
    MyCustomScene(QObject *parent = nullptr) : QGraphicsScene(parent)
    {
        backgroundColor = Qt::lightGray;
        setSceneRect(-200, -150, 400, 300); // シーンの範囲を設定
    }

    void setCustomBackgroundColor(const QColor &color)
    {
        if (backgroundColor != color) {
            backgroundColor = color;
            // シーンの背景が変更されたことをQtに通知
            update(); // シーン全体を再描画
            qDebug() << "Scene background color changed to: " << color.name();
        }
    }

protected:
    void drawBackground(QPainter *painter, const QRectF &rect) override
    {
        Q_UNUSED(rect); // 描画する矩形領域 (ビューポート内のシーン座標)

        painter->fillRect(sceneRect(), backgroundColor); // シーン全体を背景色で塗りつぶし
        // カスタムなグリッド描画などをここに追加できます
        painter->setPen(Qt::darkGray);
        painter->drawLine(sceneRect().center().x(), sceneRect().top(),
                          sceneRect().center().x(), sceneRect().bottom());
        painter->drawLine(sceneRect().left(), sceneRect().center().y(),
                          sceneRect().right(), sceneRect().center().y());
    }

private:
    QColor backgroundColor;
};

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

    MyCustomScene scene;

    QGraphicsView view1(&scene);
    view1.setRenderHint(QPainter::Antialiasing);
    view1.setWindowTitle("View 1");
    view1.show();

    QGraphicsView view2(&scene); // 同じシーンを共有する別のビュー
    view2.setRenderHint(QPainter::Antialiasing);
    view2.setWindowTitle("View 2");
    view2.show();

    // 1.5秒ごとにシーンの背景色を変更し、update()を呼び出す
    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&]() {
        static int colorIndex = 0;
        QColor colors[] = {Qt::lightGray, Qt::darkGray, Qt::cyan, Qt::magenta};
        scene.setCustomBackgroundColor(colors[colorIndex % 4]);
        colorIndex++;
    });
    timer.start(1500);

    return a.exec();
}

QGraphicsView::updateScene() は、QGraphicsSceneからビューへの更新要求が何らかの理由で正しく伝わらない場合に、**ビュー側から強制的にシーンの再描画を促すための「最終手段」**のような位置づけです。

通常、QGraphicsItemQGraphicsSceneupdate()を呼び出すと、Qtの内部メカニズムが、変更された領域を適切に特定し、その情報が関連するすべてのQGraphicsViewに伝達されます。各QGraphicsViewは、その情報に基づいて自身のビューポートの再描画をスケジュールします。このプロセスは非常に効率的で、開発者が手動でQGraphicsView::updateScene()を呼び出す必要はほとんどありません。

  • 複数のビューが同じシーンを参照しており、あるビューに固有の、シーンからのデータではない変更に基づいて、そのビューがシーンの特定の領域を更新する必要がある場合。
  • 非常に特殊なレンダリングシナリオで、ビューがシーンの特定の領域の更新を「強制」する必要がある場合(ただし、これは通常、より良い設計パターンで回避できます)。