当前位置: 首页 > news >正文

【QA】Qt中有哪些命令模式的运用?

在 C++/Qt 中,命令模式(Command Pattern)的实现通常用于封装操作请求、支持撤销/重做(Undo/Redo)或解耦调用者与接收者。以下是几种常见的实现方式及示例:


1. Qt 的 QUndoCommandQUndoStack(内置的撤销/重做框架)

这是 Qt 中命令模式的最典型实现,用于管理可撤销的操作。

  • 核心类

    • QUndoCommand:基类,表示一个可撤销的命令,需实现 undo()redo()
    • QUndoStack:管理命令历史记录的栈,支持撤销/重做。
  • 示例代码

    class AddItemCommand : public QUndoCommand {
    public:
        AddItemCommand(QListWidget *listWidget, const QString &text, QUndoCommand *parent = nullptr)
            : QUndoCommand("Add Item", parent), m_listWidget(listWidget), m_text(text) {}
        
        void redo() override {
            m_listWidget->addItem(m_text);
        }
        
        void undo() override {
            QListWidgetItem *item = m_listWidget->takeItem(m_listWidget->count() - 1);
            delete item;
        }
    
    private:
        QListWidget *m_listWidget;
        QString m_text;
    };
    
    // 使用示例
    QUndoStack undoStack;
    QListWidget listWidget;
    
    // 执行命令
    undoStack.push(new AddItemCommand(&listWidget, "New Item"));
    
    // 撤销
    undoStack.undo();
    
    // 重做
    undoStack.redo();
    

2. Qt 的 QAction(动作框架)

QAction 封装了用户触发的操作(如菜单项点击),可绑定到多个控件(菜单、工具栏按钮等),本质上是命令模式的轻量级应用。

  • 核心思想

    • QAction 将操作(如“复制”)封装为对象,通过信号 triggered() 触发执行。
    • 可绑定快捷键、图标、文本等,统一管理状态(启用/禁用)。
  • 示例代码

    QAction *copyAction = new QAction("Copy", this);
    copyAction->setShortcut(QKeySequence::Copy);
    connect(copyAction, &QAction::triggered, this, &MyWidget::copy);
    
    // 将动作添加到菜单和工具栏
    menuBar()->addAction(copyAction);
    toolBar()->addAction(copyAction);
    

3. 自定义命令接口(通用实现)

若需更灵活的控制,可自定义命令基类,并手动管理命令队列。

  • 实现步骤

    1. 定义抽象命令接口。
    2. 实现具体命令类。
    3. 使用调用者(Invoker)触发命令。
  • 示例代码

    // 1. 定义命令接口
    class Command {
    public:
        virtual ~Command() {}
        virtual void execute() = 0;
        virtual void undo() = 0;
    };
    
    // 2. 具体命令类:改变文本
    class ChangeTextCommand : public Command {
    public:
        ChangeTextCommand(QLabel *label, const QString &newText)
            : m_label(label), m_oldText(label->text()), m_newText(newText) {}
        
        void execute() override {
            m_label->setText(m_newText);
        }
        
        void undo() override {
            m_label->setText(m_oldText);
        }
    
    private:
        QLabel *m_label;
        QString m_oldText;
        QString m_newText;
    };
    
    // 3. 调用者(如按钮点击触发命令)
    QPushButton button("Change Text");
    QLabel label("Original Text");
    Command *cmd = new ChangeTextCommand(&label, "New Text");
    
    QObject::connect(&button, &QPushButton::clicked, [cmd]() {
        cmd->execute();
    });
    

4. 信号与槽的封装

通过将槽函数包装为命令对象,结合 QObject::connect 实现解耦。

  • 示例场景

    • 将复杂操作封装为命令对象,通过信号触发执行。
    • 使用 QSharedPointer 管理命令生命周期。
    class CommandWrapper : public QObject {
        Q_OBJECT
    public:
        CommandWrapper(Command *cmd) : m_cmd(cmd) {}
    
    public slots:
        void execute() { m_cmd->execute(); }
        void undo() { m_cmd->undo(); }
    
    private:
        QSharedPointer<Command> m_cmd;
    };
    
    // 连接信号到命令
    CommandWrapper wrapper(new ChangeTextCommand(&label, "New Text"));
    QObject::connect(&button, &QPushButton::clicked, &wrapper, &CommandWrapper::execute);
    

5. 宏命令(Composite Command)

将多个命令组合成一个宏命令,实现批量操作。

  • 示例代码
    class MacroCommand : public Command {
    public:
        void addCommand(Command *cmd) {
            m_commands.append(cmd);
        }
        
        void execute() override {
            for (auto cmd : m_commands) {
                cmd->execute();
            }
        }
        
        void undo() override {
            for (auto it = m_commands.rbegin(); it != m_commands.rend(); ++it) {
                (*it)->undo();
            }
        }
    
    private:
        QList<Command*> m_commands;
    };
    
    // 使用示例
    MacroCommand *macro = new MacroCommand;
    macro->addCommand(new Command1);
    macro->addCommand(new Command2);
    macro->execute();
    

总结

在 Qt 中应用命令模式的核心思想是:

  1. 封装操作:将请求封装为对象(如 QUndoCommand)。
  2. 解耦调用者与接收者:通过信号/槽或直接调用命令接口。
  3. 支持扩展:通过组合或继承实现复杂逻辑(如宏命令)。

根据需求选择合适的方式,若需要撤销/重做,优先使用 QUndoStack;若需简单解耦,可通过 QAction 或自定义命令类实现。

http://www.dtcms.com/a/86123.html

相关文章:

  • AI日报 - 2025年3月24日
  • Langchain4J框架相关面试题
  • 施磊老师高级c++(五)
  • 知识库已上线
  • 同步双写与删缓存在缓存一致性的实践对比
  • linux---------进程概念(上)
  • Linux内核,内存分布
  • Python与数据库
  • ubuntu虚拟机上定制文件系统
  • AI Agent开发大全第六课-AI对话界面参数全解析
  • 解锁二叉树:高效存储与搜索的秘密武器
  • 物化视图详解:数据库性能优化的利器
  • Vs code搭建uniapp-vue项目
  • 【Linux网络-五种IO模型与阻塞IO】
  • 23种设计模式-生成器(Builder)设计模式
  • k8s kubernetes dashboard一直CarshLoopBackoff
  • 【强化学习】重要性采样(Importing Sample)
  • uniapp从 vue2 项目迁移到 vue3流程
  • 计算机二级web易错点(6)-选择题
  • 分库分表后,跨库查询和分布式事务解决方案
  • 详解内联容器标签<span>的用法
  • TruPlasma MF 7000 7150 (G2)软件
  • 《需求工程实战指南:从理论到避坑,附大创项目案例》
  • yolo目标检测算法在DJI上的研究分析(大纲)
  • 银河麒麟桌面版包管理器(三)
  • 算力100问☞第93问:算力资源为何更分散了?
  • TensorFlow面试题及参考答案
  • 练习-日期统计
  • (C语言)习题练习 sizeof 和 strlen
  • 虚拟机安装centos7