【Qt】QUndoCommand、QUndoStack使用介绍-用于实现撤销与重做功能

QUndoCommand 是 Qt 框架中用于实现 撤销/重做(Undo/Redo) 功能的核心类,属于 QtWidgets 模块。它基于命令模式,通过封装用户操作(如文本编辑、图形移动等)来实现操作的撤销和重做管理。


核心概念

  1. 命令(Command)
    每个 QUndoCommand 子类代表一个可撤销的操作(如添加/删除文本、移动图形)。
  2. 命令栈(QUndoStack)
    存储命令的历史记录,管理撤销/重做操作。
  3. 生命周期
    • redo():首次执行命令或重做时调用
    • undo():撤销命令时调用
    • 命令对象由 QUndoStack 管理内存(无需手动删除)

使用步骤

  1. 创建自定义命令类(继承 QUndoCommand
  2. 实现 redo()undo()
    • redo() 执行操作
    • undo() 撤销操作
  3. 使用 QUndoStack 管理命令
    • push() 提交命令(自动执行 redo()
    • undo()/redo() 触发对应操作

示例:文本编辑器的撤销/重做

以下实现一个支持撤销/重做的文本插入功能:

1. 自定义命令类(插入文本)
#include 
#include 

class InsertCommand : public QUndoCommand {
public:
    InsertCommand(QTextEdit *editor, const QString &text, QUndoCommand *parent = nullptr)
        : QUndoCommand(parent), m_editor(editor), m_text(text) {
        setText("Insert Text"); // 命令描述(显示在菜单中)
    }

    void redo() override {
        // 执行插入操作
        m_editor->textCursor().insertText(m_text);
    }

    void undo() override {
        // 撤销:删除插入的文本
        QTextCursor cursor = m_editor->textCursor();
        cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, m_text.length());
        cursor.removeSelectedText();
    }

private:
    QTextEdit *m_editor;
    QString m_text;
};
2. 主窗口中使用命令栈
#include 
#include 

class MainWindow : public QMainWindow {
public:
    MainWindow() {
        // 初始化组件
        m_textEdit = new QTextEdit(this);
        setCentralWidget(m_textEdit);

        // 创建命令栈
        m_undoStack = new QUndoStack(this);

        // 添加撤销/重做按钮
        QToolBar *toolBar = addToolBar("Edit");
        toolBar->addAction(m_undoStack->createUndoAction(this, tr("Undo")));
        toolBar->addAction(m_undoStack->createRedoAction(this, tr("Redo")));

        // 插入文本的按钮
        QPushButton *insertBtn = new QPushButton("Insert 'Hello'", this);
        connect(insertBtn, &QPushButton::clicked, this, &MainWindow::insertText);
        toolBar->addWidget(insertBtn);
    }

private slots:
    void insertText() {
        // 创建命令并提交到栈(自动执行 redo())
        QUndoCommand *cmd = new InsertCommand(m_textEdit, "Hello");
        m_undoStack->push(cmd);
    }

private:
    QTextEdit *m_textEdit;
    QUndoStack *m_undoStack;
};

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

关键功能扩展

1. 命令合并(合并连续操作)
class AppendCommand : public QUndoCommand {
    // ...(类似 InsertCommand)

    int id() const override { return 1; } // 相同命令的ID

    bool mergeWith(const QUndoCommand *other) override {
        if (other->id() != id()) return false;
        // 合并连续插入的文本
        m_text += static_cast<const AppendCommand*>(other)->m_text;
        return true;
    }
};

// 提交命令时启用合并
m_undoStack->push(new AppendCommand(editor, "A")); // 第一次插入
m_undoStack->push(new AppendCommand(editor, "B")); // 合并为 "AB"
2. 宏命令(组合多个操作)
QUndoCommand *macro = new QUndoCommand("Multi-Edit");
new InsertCommand(editor, "Hello", macro); // 子命令1
new DeleteCommand(editor, 5, macro);       // 子命令2

m_undoStack->push(macro); // 整体撤销/重做

最佳实践

  1. 命令轻量化
    命令对象应只存储必要数据(如文本内容、位置),而非整个文档。
  2. 更新界面状态
    QUndoStackindexChanged() 信号中更新撤销/重做按钮状态。
  3. 清理历史
    使用 QUndoStack::setClean() 标记保存点,避免不必要的撤销。

通过 QUndoCommand,您可以轻松为 Qt 应用程序添加专业的撤销/重做功能,提升用户体验。

你可能感兴趣的:(【Qt】QUndoCommand、QUndoStack使用介绍-用于实现撤销与重做功能)