首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为FitInView特性在Qt中使用命令模式的撤消-重做功能

为FitInView特性在Qt中使用命令模式的撤消-重做功能
EN

Stack Overflow用户
提问于 2022-05-08 07:59:11
回答 1查看 127关注 0票数 0

我有QGraphicsView,它包含一些QGraphicsItem。该视图具有一些特性,如zoom-inzoom-outfitInUndo-Redo

我的fitIn特性在Undo-Redo功能中不起作用。

(为了实现Undo-Redo,我在Qt中使用了Command-Pattern。)

myCommand.h

代码语言:javascript
复制
class myCommand: public QUndoCommand
{
public:
    myCommand();
    myCommand(QTransform t, int hr, int vr, QGraphicsView* v);
    void undo();
    void redo();
    QTransform t;
    int hScrollBar;
    int  vScrollBar;
    QGraphicsView* mView;
};

myCommand.cpp

代码语言:javascript
复制
myCommand::myCommand(QTransform t, int hr, int vr, QGraphicsView *v)
{
    this->t = t;
    this->hScrollBar= hr;
    this->vScrollBar= vr;
    this->mView = v;
}

void myCommand::undo()
{
    mView->setTransform(t);
    mView->horizontalScrollBar()->setValue(hScrollBar);
    mView->verticalScrollBar()->setValue(vScrollBar);
}

void myCommand::redo()
{
   myView mv;
   mv.FitInView();
}

myView.cpp

代码语言:javascript
复制
 void myView::FitIn()
    {
        FitInView();
        QTransform t = view->transform();
        int hrValue = view->horizontalScrollBar()->value();
        int vrValue = view->verticalScrollBar()->value();
        myCommand* Command1 = new myCommand(t,hrValue,vrValue,view);
        undoStack->push(Command1);   
    }

void myView::DrawDesign()
{
   // Logic for inserting all the Rectangles and polylines.
   QTimer::singleShot(100, this, [&]() {
        FitInView();
    });
}

void myView::FitInView()
{
    QRectF bounds = scene->sceneRect();
    QRectF rect  {0,0,200,200};
    if (bounds.width() < 200)
    {
        rect .setWidth(bounds.width());
        bounds.setWidth(200);
    }
    if (bounds.height() < 200)
    {
        rect.setWidth(bounds.height());
        bounds.setHeight(200);
    }
    view->fitInView(bounds, Qt::KeepAspectRatio);
    view->updateGeometry();
}

myView.h

代码语言:javascript
复制
public:
      QUndoStack* undoStack;

FitInView非常适合我的设计,但它在Undo-Redo特性中不起作用。

我想我在myCommand::undo()myCommand::redo()函数上犯了一个错误。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-08 12:57:48

基于您在Qt撤消框架上发布的许多问题,在我看来,您缺少了命令模式的一个重要部分:

命令模式基于这样的思想,即通过创建命令对象的实例()来完成应用程序中的所有编辑。命令对象将更改应用于文档,并存储在命令堆栈中。此外,每个命令都知道如何撤消其更改以使文档恢复到以前的状态。[1]

因此,所有的更改都应该在QUndoCommand内部实现(按照链接来发现一个基本的用法示例),即在QUndoCommand::redo内部。使用QUndoStack将命令推送到QUndoStack::push上后,更改(即QCommand::redo)将自动执行:

cmd推到堆栈上,或将其与最近执行的命令合并。在这两种情况下,都通过调用其redo()函数执行. [4.]

创建新QUndoCommand的步骤

  1. QUndoCommand::redo (而不是其他地方)中实现所需的更改。
  2. QUndoCommand::undo中编写此命令的逆命令。如果需要,捕获QUndoCommand构造函数中的初始状态,以便轻松恢复QUndoCommand::redo

应用于您的示例

因此,myView::FitIn应该执行的唯一操作是将命令推到撤销堆栈上:

代码语言:javascript
复制
void myView::FitIn()
{
    undoStack->push(new fitCommand(view));   
}

在redo命令中实现更改:

代码语言:javascript
复制
void fitCommand::redo()
{
    mView->FitInView(); // Can be implemented using QGraphicsView::fitInView
}

由于拟合的逆操作不是唯一定义的,所以我们在QUndoCommand构造函数中存储初始状态(以便能够在QUndoCommand::undo中恢复初始状态):

代码语言:javascript
复制
fitCommand::fitCommand(myView *view)
{
    this->t = view->transform();
    this->hScrollBar= view->horizontalScrollBar()->value();
    this->vScrollBar= view->verticalScrollBar()->value();
    this->mView = view;
}

现在我们可以实现undo命令来恢复redo命令:

代码语言:javascript
复制
void fitCommand::undo()
{
    mView->setTransform(t);
    mView->horizontalScrollBar()->setValue(hScrollBar);
    mView->verticalScrollBar()->setValue(vScrollBar);
}

有用的阅读材料:

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72159106

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档