C++プログラミングでやり直しが可能なUndo/Redo機能を実装!QUndoGroup::canRedo()の使い方


QUndoGroup::canRedo()関数は、Qt GUIにおけるUndo/Redo機能を管理するQUndoGroupクラスにおいて、現在のアクティブなスタックやり直せるかどうかを判断します。つまり、過去に行われた操作をやり直すことができるかどうかを確認する関数です。

戻り値

  • false: やり直し不可
  • true: やり直しが可能

詳細

QUndoGroup::canRedo()関数は、現在のアクティブなスタックの状態に基づいて、やり直しが可能かどうかを判断します。アクティブなスタックとは、QUndoGroupが現在操作しているQUndoStackオブジェクトです。QUndoStackには、過去に行われた操作が記録されており、これらの操作をやり直すことができます。

QUndoStackが空の場合、またはやり直せる操作が存在しない場合は、QUndoGroup::canRedo()関数はfalseを返します。

QUndoGroup group;
QUndoStack stack1;
QUndoStack stack2;

// stack1に操作を追加
stack1.push(new MyUndoCommand);

// groupにstack1を追加
group.addStack(&stack1);

// stack2に操作を追加
stack2.push(new MyUndoCommand);

// groupにstack2を追加
group.addStack(&stack2);

// アクティブなスタックをstack1に設定
group.setActiveStack(&stack1);

// stack1の操作をやり直せるかどうかを確認
bool canRedo = group.canRedo();

if (canRedo) {
  // stack1の操作をやり直す
  group.redo();
} else {
  // stack1の操作をやり直せない
}
  • QUndoGroup::createRedoAction()関数は、やり直しアクションを作成します。このアクションをクリックすると、現在のアクティブなスタックの操作がやり直されます。
  • QUndoGroup::canRedo()関数は、シグナルcanRedoChanged(bool)をemitします。このシグナルは、やり直せる状態が変化したときにemitされます。
  • QUndoGroup::createRedoAction(): やり直しアクションを作成します。
  • QUndoGroup::createUndoAction(): やり直しアクションを作成します。
  • QUndoGroup::setActiveStack(): アクティブなスタックを設定します。
  • QUndoGroup::redo(): 現在のアクティブなスタックの操作をやり直します。
  • QUndoGroup::undo(): 現在のアクティブなスタックの操作をやり直します。
  • QUndoGroup::canUndo(): やり直せるかどうかを確認します。


#include <QApplication>
#include <QUndoGroup>
#include <QUndoStack>
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QPushButton>

class MyUndoCommand : public QUndoCommand
{
public:
    MyUndoCommand(const QString& text, QPlainTextEdit* editor)
        : text(text), editor(editor)
    {}

    virtual void undo() override
    {
        editor->setPlainText(text);
    }

    virtual void redo() override
    {
        editor->setPlainText(newText);
    }

private:
    QString text;
    QString newText;
    QPlainTextEdit* editor;
};

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

    QMainWindow window;
    QPlainTextEdit editor(&window);
    QPushButton undoButton(&window);
    QPushButton redoButton(&window);

    undoButton.setText("Undo");
    redoButton.setText("Redo");

    QUndoGroup group;
    QUndoStack stack;

    QObject::connect(&undoButton, &QPushButton::clicked, &group, &QUndoGroup::undo);
    QObject::connect(&redoButton, &QPushButton::clicked, &group, &QUndoGroup::redo);

    QVBoxLayout layout(&window);
    layout.addWidget(&editor);
    layout.addWidget(&undoButton);
    layout.addWidget(&redoButton);

    window.setLayout(&layout);
    window.show();

    // 操作を追加
    MyUndoCommand* command1 = new MyUndoCommand(editor.toPlainText(), &editor);
    stack.push(command1);
    group.addStack(&stack);

    // 操作を追加
    MyUndoCommand* command2 = new MyUndoCommand(editor.toPlainText(), &editor);
    stack.push(command2);

    return app.exec();
}

このコードは、以下の操作を行います。

  1. QMainWindowとQPlainTextEdit、QPushButtonなどのウィジェットを作成します。
  2. QUndoGroupとQUndoStackオブジェクトを作成します。
  3. UndoボタンとRedoボタンを作成し、QUndoGroup::undo()とQUndoGroup::redo()シグナルに接続します。
  4. MyUndoCommandオブジェクトを作成し、QUndoStackにプッシュします。
  5. MyUndoCommandオブジェクトを作成し、QUndoStackにプッシュします。

このコードを実行すると、以下のようになります。

  1. テキストエディタにテキストを入力できます。
  2. Undoボタンをクリックすると、入力したテキストが取り消されます。
  3. Redoボタンをクリックすると、取り消されたテキストが元に戻されます。
#include <QApplication>
#include <QUndoGroup>
#include <QUndoStack>
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QLabel>

class MyUndoCommand : public QUndoCommand
{
public:
    MyUndoCommand(const QString& text, QPlainTextEdit* editor)
        : text(text), editor(editor)
    {}

    virtual void undo() override
    {
        editor->setPlainText(text);
    }

    virtual void redo() override
    {
        editor->setPlainText(newText);
    }

private:
    QString text;
    QString newText;
    QPlainTextEdit* editor;
};

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

    QMainWindow window;
    QPlainTextEdit editor(&window);
    QPushButton undoButton(&window);
    QPushButton redoButton(&window);
    QLabel canRedoLabel(&window);

    undoButton.setText("Undo");
    redoButton.setText("Redo");
    canRedoLabel.setText("Redo可能: ");

    QUndoGroup group;
    QUndoStack stack;

    QObject::connect(&undoButton, &QPushButton::clicked, &group, &QUndoGroup::undo);
    QObject::connect(&redoButton, &QPushButton::clicked, &group, &QUndoGroup::redo);

    QObject::connect(&group, &QUndoGroup::canRedoChanged,
                     &canRedoLabel, &QLabel::setText);

    QVBoxLayout layout(&window);
    layout.addWidget(&editor);
    layout.addWidget(&undoButton);
    layout.addWidget(&redoButton);
    layout


  • スタック内の操作の依存関係を考慮しない
  • 現在のアクティブなスタックのみを対象とする

これらの欠点を克服するために、QUndoGroup::canRedo()関数の代替方法をいくつか紹介します。

QUndoStack::canRedo()関数を使用する

QUndoStack::canRedo()関数は、指定されたスタックやり直せるかどうかを判断します。この関数は、QUndoGroup::canRedo()関数よりも柔軟性があります。

bool canRedo = stack.canRedo();

独自のロジックを実装する

QUndoGroup::canRedo()関数の代替として、独自のロジックを実装することもできます。この方法は、より複雑なシナリオに対応する必要がある場合に役立ちます。

bool canRedo()
{
    // 独自のロジックを実装
}

QUndoModelクラスを使用する

QUndoModelクラスは、Undo/Redoモデルを表すクラスです。このクラスには、QUndoGroup::canRedo()関数よりも多くの機能が含まれています。

QUndoModel model;

// ...

bool canRedo = model.canRedo();

QUndoViewクラスを使用する

QUndoView view(&model);

// ...

bool canRedo = view.canRedo();

どの方法を選択するべきか

どの代替方法を選択するかは、具体的な状況によって異なります。

  • モデルベースのUndo/Redo機能が必要な場合、QUndoModelクラスまたはQUndoViewクラスを使用する必要があります。
  • より複雑なシナリオの場合、独自のロジックを実装する必要があります。
  • シンプルなシナリオの場合、QUndoStack::canRedo()関数を使用するのが最善**です。