利用Qt Undo FrameWork解决数据回滚问题(撤销恢复)

最近在做功能时,有个这样的场景:用户修改一部分的数据,需要支持用户对修改数据的撤销与恢复。

思考了很久,发现可以用Qt的Qt Undo Framework处理。做了如下总结:

     上述的业务场景实际可以抽象为对用户数据的撤销与恢复。类似问题可以用命令模式处理。

      实现这一功能的关键是将一个命令看作一个对象并记录详细内容。具体的来说,需要记录一个命令影响了系统中的那些对象,该命令修改了这些对象的那些数据成员,这些数据成员在执行命令前后的取值是什么。一旦记录了这些信息,可以撤销或重做这条命令。目前Qt Undo Framework利用了命令设计模式处理该问题。

 

类图说明



核心类

QUndoCommand:这个类相当于Command模式中的那个抽象基类Command,所有这些命令都被保存到undo栈中,在其派生类中实现undo和redo函数。

QUndoStack:这个相当于命令历史记录,其中保存了Command对象的列表。

QUndoGroup:是一个undo stack的组合。

QUndoView:是显示undo堆栈中内容的一个列表组件,在这个视图中点击命令的名称也可以实现与Undo/Redo按钮相同的作用。


场景测试

为简化场景,用如下的场景代替。Map(oRuleIDMap)中存放规则ID与规则名称的对应关系,数据如下:

oRuleIDMap.insert(std::make_pair(0, "ModifyEdoName"));        //0-修改图元名称

oRuleIDMap.insert(std::make_pair(1, "ModifyEdoVisible"));        //1-修改图元可见性

oRuleIDMap.insert(std::make_pair(2, "ModifyEntName"));         //2-修改构件名称

oRuleIDMap.insert(std::make_pair(3, "ModifyEntVisible"));         //3-修改构件名称

 

执行操作:修改规则的所有名称,后缀添加”_Default”。修改后数据如下(相当于用户修改了规则参数并且点击确定按钮

std::make_pair(0, "ModifyEdoName_Default")             //0-修改图元名称_Default

std::make_pair(1, "ModifyEdoVisible_Default")            //1-修改图元可见性_Default

std::make_pair(2, "ModifyEntName_Default")             //2-修改构件名称_Default

std::make_pair(3, "ModifyEntVisible_Default")             //3-修改构件名称_Default

 

执行操作:撤销上部的所有修改记录,即后缀去掉”_Default”。修改后数据如下(相当于用户修改了规则参数并且点击取消按钮

std::make_pair(0, "ModifyEdoName")               //0-修改图元名称

std::make_pair(1, "ModifyEdoVisible")              //1-修改图元可见性

std::make_pair(2, "ModifyEntName")               //2-修改构件名称

std::make_pair(3, "ModifyEntVisible")               //3-修改构件名称


代码示例

<p>#include <QUndoStack></p><p>#include <QUndoCommand></p><p>#include <QDebug></p>
typedef std::map<int, QString> MyRuleDataMap;
class MyModifyCommand: public QUndoCommand
{
public:
    MyModifyCommand(MyRuleDataMap* oRuleDataMap, int nRuleID, const QString& sOldValue, const QString& sNewValue);

    virtual void undo();
    virtual void redo();
private:
    int m_nRuleID;
    QString m_sOldValue, m_sNewValue;
    MyRuleDataMap* m_pRuleDataMap;
};

MyModifyCommand::MyModifyCommand(MyRuleDataMap* oRuleDataMap, int nRuleID, 
    const QString& sOldValue, const QString& sNewValue)
    :QUndoCommand(nullptr), m_pRuleDataMap(oRuleDataMap), m_nRuleID(nRuleID), m_sOldValue(sOldValue), m_sNewValue(sNewValue)
{

}

void MyModifyCommand::undo()
{
    auto pIter = m_pRuleDataMap->find(m_nRuleID);
    if (pIter != m_pRuleDataMap->end())
    {
        pIter->second = m_sOldValue;
    }
}

void MyModifyCommand::redo()
{
    auto pIter = m_pRuleDataMap->find(m_nRuleID);
    if (pIter != m_pRuleDataMap->end())
    {
        pIter->second = m_sNewValue;
    }
}

void outputAllRuleData(MyRuleDataMap& oRuleMap)
{
    for(auto it = oRuleMap.begin(); it != oRuleMap.end(); ++it)
    {
        int nRuleID = it->first;
        QString sRuleData = it->second;
        qDebug() << "RuleID:" << nRuleID << "   RuleData:" << sRuleData;
    }
}

int main(int argc, char *argv[])
{
    std::shared_ptr<MyRuleDataMap> pRuleDataMap(new MyRuleDataMap);
    pRuleDataMap->insert(std::make_pair(0, "ModifyEdoName"));        //0-修改图元名称
    pRuleDataMap->insert(std::make_pair(1, "ModifyEdoVisible"));     //1-修改图元可见性
    pRuleDataMap->insert(std::make_pair(2, "ModifyEntName"));        //2-修改构件名称 
    pRuleDataMap->insert(std::make_pair(3, "ModifyEntVisible"));     //3-修改构件名称

    qDebug() << QStringLiteral("修改前原始数据:");
    outputAllRuleData(*pRuleDataMap.get());
    qDebug() << "===================================================";

    std::shared_ptr<QUndoStack> pUndoStack(new QUndoStack);
    MyModifyCommand* pModifyRuleID0 = new MyModifyCommand(pRuleDataMap.get(), 0, "ModifyEdoName", "ModifyEdoName_Default");
    pUndoStack->push(pModifyRuleID0);

    MyModifyCommand* pModifyRuleID1 = new MyModifyCommand(pRuleDataMap.get(), 1, "ModifyEdoVisible", "ModifyEdoVisible_Default");
    pUndoStack->push(pModifyRuleID1);

    MyModifyCommand* pModifyRuleID2 = new MyModifyCommand(pRuleDataMap.get(), 2, "ModifyEntName", "ModifyEntName_Default");
    pUndoStack->push(pModifyRuleID2);

    MyModifyCommand* pModifyRuleID3 = new MyModifyCommand(pRuleDataMap.get(), 3, "ModifyEntVisible", "ModifyEntVisible_Default");
    pUndoStack->push(pModifyRuleID3);

    qDebug() << QStringLiteral("修改原始数据:");
    outputAllRuleData(*pRuleDataMap.get());
    qDebug() << "===================================================";

    pUndoStack->undo();
    pUndoStack->undo();
    pUndoStack->undo();
    pUndoStack->undo();
    qDebug() << QStringLiteral("撤销修改数据:");
    outputAllRuleData(*pRuleDataMap.get());
    qDebug() << "===================================================";

    return 1;
}

测试结果

"修改前原始数据:"

RuleID: 0    RuleData: "ModifyEdoName"

RuleID: 1    RuleData: "ModifyEdoVisible"

RuleID: 2    RuleData: "ModifyEntName"

RuleID: 3    RuleData: "ModifyEntVisible"

===================================================

"修改原始数据:"

RuleID: 0    RuleData: "ModifyEdoName_Default"

RuleID: 1    RuleData: "ModifyEdoVisible_Default"

RuleID: 2    RuleData: "ModifyEntName_Default"

RuleID: 3    RuleData: "ModifyEntVisible_Default"

===================================================

"撤销修改数据:"

RuleID: 0    RuleData: "ModifyEdoName"

RuleID: 1    RuleData: "ModifyEdoVisible"

RuleID: 2    RuleData: "ModifyEntName"

RuleID: 3    RuleData: "ModifyEntVisible"

===================================================


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回滚操作是Oracle数据库中常见的操作之一,但是如果回滚数据量很大或者回滚的事务等待时间过长,就会导致Oracle响应变慢,甚至出现长时间无响应的情况。以下是一些可能的解决方法: 1. 提高回滚段的大小:可以通过增加回滚段的大小来提高回滚性能,从而加快回滚操作的速度。可以使用如下命令来增加回滚段的大小: ALTER ROLLBACK SEGMENT segment_name ADD DATAFILE 'datafile_name' SIZE size; 2. 使用更快的存储设备:可以将回滚段放置在更快的存储设备上,如固态硬盘,以提高回滚性能。 3. 优化SQL语句:如果发现回滚操作主要是由于某个SQL语句引起的,可以通过优化SQL语句来减少回滚数据量,从而提高回滚性能。 4. 调整Undo_retention参数:可以通过调整Undo_retention参数来减少回滚操作的时间。该参数控制了回滚段中事务的最长存活时间,如果该时间过长,回滚操作的速度就会变慢。 5. 增加回滚段的数量:可以通过增加回滚段的数量来提高回滚性能,从而减少回滚操作的时间。 6. 使用Flashback技术:如果Oracle数据库支持Flashback技术,可以使用该技术来快速回滚数据,从而加快回滚操作的速度。 以上是一些可能的解决方法,但具体应该根据实际情况进行选择。如果问题持续存在,建议联系Oracle技术支持或专业的数据库管理员进行进一步的诊断和解决

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值