Qt GUIプログラミングにおけるUNDO/REDO機能の賢い実装:QUndoStack::setClean()の活用法


QUndoStack::setClean()は、QUndoStackクラスのメソッドで、スタックを「クリーン」な状態にマークします。これは、通常、ドキュメントが保存された時点の状態を表します。

クリーン状態とは

クリーン状態とは、スタックに元に戻せるコマンドが存在しない状態です。言い換えると、ユーザーによる変更が保存されている状態です。

setClean()の役割

setClean()を呼び出すことで、以下のことが行われます。

  • cleanChanged()シグナルがemitされます。このシグナルは、スタックがクリーンまたは非クリーンになったときにemitされます。
  • スタックがクリーンであることを示すフラグが設定されます。

setClean()の使いどころ

setClean()は、以下の場面で使用されます。

  • スタックを初期化するとき
  • ユーザーが新しい作業を開始するとき
  • ドキュメントが保存されたとき

QUndoStack stack;

// ... ユーザーによる操作 ...

stack.setClean();

この例では、ユーザーによる操作の後、setClean()を呼び出して、スタックをクリーンな状態にしています。

  • cleanIndex()メソッドを使用して、クリーンな状態のインデックスを取得できます。
  • isClean()メソッドを使用して、スタックがクリーンかどうかを確認できます。
  • 上記の説明は、Qt GUI 6.7.2を対象としています。他のバージョンでは、機能や使用方法が異なる場合があります。


#include <QApplication>
#include <QMainWindow>
#include <QTextEdit>
#include <QUndoStack>
#include <QUndoView>

class MainWindow : public QMainWindow
{
public:
    MainWindow();

private:
    QTextEdit *textEdit;
    QUndoStack *undoStack;
    QUndoView *undoView;
};

MainWindow::MainWindow()
{
    textEdit = new QTextEdit;
    undoStack = new QUndoStack;
    undoView = new QUndoView(undoStack);

    setCentralWidget(textEdit);

    QToolBar *toolBar = new QToolBar;
    toolBar->addAction(undoStack->undoAction());
    toolBar->addAction(undoStack->redoAction());
    addToolBar(Qt::TopToolBarArea, toolBar);

    connect(textEdit, &QTextEdit::textChanged, undoStack, &QUndoStack::push);

    // ドキュメントが保存されたときにスタックをクリーンにする
    connect(textEdit, &QTextDocument::saveCompleted, undoStack, &QUndoStack::setClean);
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.show();
    return app.exec();
}

このコードでは、以下のことが行われています。

  1. MainWindowクラスが作成されます。
  2. textEditundoStackundoView オブジェクトが作成されます。
  3. textEditMainWindow の中央ウィジェットとして設定されます。
  4. ツールバーが作成され、undoredo アクションが追加されます。
  5. textEdittextChanged シグナルが undoStackpush スロットに接続されます。
  6. QTextDocumentsaveCompleted シグナルが undoStacksetClean スロットに接続されます。

このコードを実行すると、テキストエディタが表示されます。テキストを編集すると、undoStack にコマンドがプッシュされます。undo ボタンをクリックすると、最後の操作が取り消されます。redo ボタンをクリックすると、取り消された操作がやり直されます。

ドキュメントを保存すると、undoStack はクリーンな状態になります。つまり、保存された時点の状態は元に戻せません。



cleanIndex() と setIndex() を使用する

cleanIndex() メソッドを使用して、スタック内のクリーンな状態のインデックスを取得できます。その後、setIndex() メソッドを使用して、スタック内の現在のインデックスをクリーンな状態のインデックスに設定できます。

int cleanIndex = undoStack->cleanIndex();
undoStack->setIndex(cleanIndex);

利点

  • コードが簡潔になる

欠点

  • cleanIndex() が常に正しい値を返すとは限らない。たとえば、スタックが破損している場合、cleanIndex() は誤った値を返す可能性があります。

新しい QUndoStack オブジェクトを作成する

新しい QUndoStack オブジェクトを作成し、既存の QUndoStack オブジェクトの内容をコピーして、新しいオブジェクトに貼り付けることができます。

QUndoStack *newStack = new QUndoStack;
newStack->push(undoStack->commands());
delete undoStack;
undoStack = newStack;

利点

  • スタックが確実にクリーンな状態になる

欠点

  • パフォーマンスが低下する可能性がある
  • コードが複雑になる

カスタムフラグを使用する

スタックがクリーンかどうかを示すカスタムフラグを作成して管理することもできます。

bool isClean = true;

// ... ユーザーによる操作 ...

if (isClean) {
    // ドキュメントを保存する
}

isClean = false;

利点

  • 柔軟性が高い

欠点

  • バグが発生しやすい
  • コードが煩雑になる

最良の代替方法は、状況によって異なります。 以下の点などを考慮して、適切な方法を選択してください。

  • 信頼性
  • パフォーマンス
  • コードの簡潔性