IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> QML使用C++model(撤销恢复) -> 正文阅读

[C++知识库]QML使用C++model(撤销恢复)

上一篇介绍了model实现排序和过滤,实际项目中model/view不止用来显示数据,还会用于实现比较复杂的界面交互,某些情况下需要支持撤销恢复的功能

Qt Undo Framework

介绍

Qt的撤销框架是命令模式的一个实现,用于在应用程序中实现撤销/重做功能。

命令模式基于这样一种思想,即应用程序中的所有编辑都是通过创建命令对象的实例来完成的。命令对象将更改应用于文档,并存储在命令堆栈中。此外,每个命令都知道如何撤销其更改,以将文档恢复到之前的状态。只要应用程序只使用命令对象来改变文档的状态,就可以通过向下遍历堆栈并依次对每个命令调用undo来撤销一系列命令。还可以通过向上遍历堆栈并对每个命令调用redo来重做一系列命令。

该框架由四类组成:

  • QUndoCommand是存储在撤消堆栈上的所有命令的基类。它可以应用(重做)或撤消文档中的单个更改。
  • QUndoStack是一个列表QUndoCommand对象。它包含对文档执行的所有命令,并且可以通过撤销或重做这些命令来向后或向前滚动文档的状态。
  • QUndoGroup?是一组撤消堆栈。当一个应用程序包含多个撤销堆栈时,这是很有用的,通常每个打开的文档都有一个撤销堆栈。QUndoGroup?为组中的所有堆栈提供一对撤消/重做插槽。它将撤销和重做请求转发到活动堆栈,该堆栈与用户当前正在编辑的文档相关联。
  • QUndoView?是一个显示撤销堆栈内容的小部件。单击视图中的命令会将文档状态向前或向后滚动到该命令。

概念

该框架支持以下概念:

  • Clean state:用于在文档进入和离开已保存到磁盘的状态时发出信号。这通常用于禁用或启用保存操作,以及更新文档的标题栏。
  • Command compression:用于将命令序列压缩成单个命令。例如:在文本编辑器中,将单个字符插入到文档中的命令可以压缩成一个插入整个文本部分的命令。这些更大的改变对于用户来说更方便撤销和重做。
  • Command macros:一系列命令,所有这些命令都可以在一个步骤中撤消或重做。这简化了编写应用程序的任务,因为一组简单的命令可以组成更复杂的命令。例如,移动文档中一组选定对象的命令可以通过组合一组命令来创建,每个命令移动一个对象。

QUndoStack提供方便的撤消和重做动作可以插入菜单或工具栏的对象。这些动作的文本属性总是反映当它们被触发时什么命令将被撤消或重做。同样的,群体提供撤消和重做操作,其行为总是类似于活动堆栈的撤消和重做操作。

以上是Qt文档的介绍

总结起来就是,所要实现撤销的操作都通过QUndoCommand进行创建,把QUndoCommand添加到撤销堆栈QUndoStack,就可以基于堆栈实现undo和redo的操作,如果有多个撤销堆栈,则还可以使用组QUndoGroup来管理多个堆栈,实现多个堆栈的undo和redo操作

接下来直接来看具体应用吧

Model搭配撤销框架

例子使用的还是之前的model,在此基础上搭配Qt的undo框架来实现undo、redo的操作

#include <QUndoCommand>
#include "datalistmodel.h"

class AddCommand : public QUndoCommand
{
public:
    AddCommand(const ModelData &modelData, DataListModel *model,
               QUndoCommand *parent = nullptr);

    void undo() override;
    void redo() override;

private:
    int m_index = -1;
    ModelData m_modelData;
    DataListModel *m_pModel = nullptr;

};

class DeleteCommand : public QUndoCommand
{
public:
    DeleteCommand(int index, DataListModel *model, QUndoCommand *parent = nullptr);

    void undo() override;
    void redo() override;

private:
    int m_index;
    ModelData m_modelData;
    DataListModel *m_pModel = nullptr;

};
#include "commands.h"

AddCommand::AddCommand(const ModelData &modelData, DataListModel *model, QUndoCommand *parent):
    QUndoCommand(parent), m_modelData(modelData), m_pModel(model)
{
    Q_ASSERT(m_pModel);
    m_index = m_pModel->rowCount();
}

void AddCommand::undo()
{
    m_pModel->remove(m_index);
}

void AddCommand::redo()
{
    Q_ASSERT(m_pModel);
    m_pModel->insert(m_index, m_modelData);
}



DeleteCommand::DeleteCommand(int index, DataListModel *model, QUndoCommand *parent):
    QUndoCommand(parent), m_index(index), m_pModel(model)
{
    Q_ASSERT(m_pModel);
    m_pModel->modelData(m_index, m_modelData);
}

void DeleteCommand::undo()
{
    Q_ASSERT(m_pModel);
    m_pModel->insert(m_index, m_modelData);
}

void DeleteCommand::redo()
{
    Q_ASSERT(m_pModel);
    m_pModel->remove(m_index);
}

这里我们对新增和删除的操作进行记录,需要继承QUndoCommand实现新增和删除的command,重写undo()和redo(),首次创建QUndoCommand会执行redo操作,即redo就是具体要记录的操作,如增加command的redo就是insert(),删除的command就是remove(),undo则是撤销的操作,就如前面说明的一样,每个命令需要知道如何撤销其更改,undo就是撤销更改的操作。

#include <QObject>

class DataListModel;
class QUndoStack;
class ModelManager : public QObject
{
    Q_OBJECT
public:
    explicit ModelManager(QObject *parent = nullptr);

    Q_INVOKABLE DataListModel *getModel() const;
    Q_INVOKABLE void add(const QVariantMap &dataMap);
    Q_INVOKABLE void remove(int index);
    Q_INVOKABLE void undo();
    Q_INVOKABLE void redo();

private:
    DataListModel *m_pDataModel = nullptr;
    QUndoStack *m_pUndoStack = nullptr;

};
#include "modelmanager.h"
#include "datalistmodel.h"
#include "commands.h"
#include "qqml.h"

#include <QUndoStack>

ModelManager::ModelManager(QObject *parent):
    QObject(parent)
{
    m_pUndoStack = new QUndoStack(this);
    m_pDataModel = new DataListModel(this);

    qmlRegisterType<DataListModel>("Model", 1, 0, "myModel");
}

DataListModel *ModelManager::getModel() const
{
    return m_pDataModel;
}

void ModelManager::add(const QVariantMap &dataMap)
{
    QString type = dataMap["type"].toString();
    QString size = dataMap["size"].toString();

    ModelData data(type, size);
    QUndoCommand *addCommand = new AddCommand(data, m_pDataModel);
    m_pUndoStack->push(addCommand);
}

void ModelManager::remove(int index)
{
    QUndoCommand *deleteCommand = new DeleteCommand(index, m_pDataModel);
    m_pUndoStack->push(deleteCommand);
}

void ModelManager::undo()
{
    m_pUndoStack->undo();
}

void ModelManager::redo()
{
    m_pUndoStack->redo();
}

把QUndoCommand添加到堆栈QUndoStack中,执行QUndoStack的undo和redo即可实现撤销恢复的功能

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "modelmanager.h"

int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

    ModelManager manager;

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("modelManager", &manager);
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

QML调用

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    ListView {
        id: listview
        clip: true
        width: parent.width
        height: parent.height

        model: modelManager.getModel()
        delegate: Item {
            id: delegate
            width: listview.width
            height: 30
            Row {
                spacing: 5
                Text {
                    text: type
                }

                Text {
                    text: size
                    color: "red"
                }

                Button  {
                    height: parent.height
                    onClicked: {
                        modelManager.remove(index);
                    }
                }


            }

        }
    }

    Row {
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 10
        spacing: 5

        Text {
            height: 40
            text: "type:"
            verticalAlignment: Text.AlignVCenter
        }

        TextField {
            id: typeInput
            width: 60
        }

        Text {
            height: 40
            text: "size:"
            verticalAlignment: Text.AlignVCenter
        }

        TextField {
            id: sizeInput
            width: 60
        }

        Button {
            text: "add"
            onClicked: {
                modelManager.add({"type": typeInput.text, "size": sizeInput.text})
            }
        }

        Button  {
            text: "undo"
            onClicked: {
                modelManager.undo()
            }
        }

        Button  {
            text: "redo"
            onClicked: {
                modelManager.redo()
            }
        }
    }
}

运行效果

?结语

以上就是一个简单的model/view搭配undo framework实现的撤销恢复功能,undo framework的例子可在Qt Creator例子搜索undo进行查看,例子是基于Graphics实现的,了解其中的用法,在model/view也能使用。?自此,QML与C++model的使用就介绍到此,目前应用到的场景就这么多,以后接触到其他功能再做记录。

完整的demo地址

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-29 18:48:02  更:2022-06-29 18:48:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/27 10:03:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码