首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Qt中使用命令模式实现隐藏QGraphicsItem的撤消-重做功能?

如何在Qt中使用命令模式实现隐藏QGraphicsItem的撤消-重做功能?
EN

Stack Overflow用户
提问于 2022-04-28 06:29:55
回答 1查看 375关注 0票数 0

我有一个QGraphicsView,其中包含一些QGraphicsItem,我有一个特性(隐藏项),鼠标右键单击,隐藏所需的QGraphicsItem(矩形)及其连接的polylines。我也有一个Undo-Redo特性。

撤销-它应该取消执行的最后一个命令的效果,并显示以前的转换。

重做-它将撤销以前的撤销。

为了实现这个Undo-Redo特性,我使用了Command pattern。我已经为Undo-Redo实现了ZoomIn-ZoomOut特性。

的问题是:我不知道如何为隐藏特性实现撤销-重做。意思是把什么推到堆栈里,拉什么?

下面的Undo-Redo代码是ZoomIn-ZoomOut特性的代码。(为了便于参考,我想实现这样的Hide特性。)

myCommand.c

代码语言:javascript
复制
class myCommand: public QUndoCommand
{
public:
    myCommand();
    myCommand(double scale, QGraphicsScene* scene,QGraphicsView* view);    
private:
       QGraphicsItem* mItem;
       QGraphicsScene* mScene;
       QGraphicsView* mView;
       double scaleFactor;
       void undo();
       void redo();  
}

myCommand.cpp

代码语言:javascript
复制
 myCommand::myCommand(double scale, QGraphicsScene *scene,QGraphicsView* view): mScene(scene),
        mView(view),scaleFactor(scale)
    {}
void guiCommand::undo()
 {
      mView->scale(1/scaleFactor,1/scaleFactor);
 }

void myCommand::redo()
{
     mView->scale(scaleFactor,scaleFactor);
}

myView.cpp

代码语言:javascript
复制
void myView::ZoomIn()
{
    double scaleFactor = 1.1;
    view->scale(scaleFactor,scaleFactor);
    myCommand* command1 = new myCommand(scaleFactor,scene,view);
    undoStack->push(command1);
}

myView.h

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

新增:

代码语言:javascript
复制
void myRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    vPtr = this->getPtr();
    if(vPtr->isVisible == false)
          this->hide();
    else
    {
        this->show();
        qDebug()<<"Undo Rect";
    }
}

myCommand是:

代码语言:javascript
复制
myCommand* command3 = new myCommand(isRectHiddden,vPtr,GraphName);
undoStack->push(command3);
EN

回答 1

Stack Overflow用户

发布于 2022-04-28 09:35:29

考虑到您已经成功地实现了缩放/缩放,这应该非常简单。

代码语言:javascript
复制
class HideItemCommand: public QUndoCommand
{
public:
    explicit HideItemCommand(QGraphicsItem *item);    
private:
    QGraphicsItem* mItem;
    void undo();
    void redo();  
}
代码语言:javascript
复制
HideItemCommand::HideItemCommand(QGraphicsItem *item): mItem(item)
{}

void HideItemCommand::undo()
{
     mItem->show();
}

void myCommand::redo()
{
     mItem->hide();
}
代码语言:javascript
复制
void myView::hideItem(QGraphicsItem* item)
{
    item->hide();
    auto cmd = new HideItemCommand(item);
    undoStack->push(cmd);
}

所以这很简单。但是!现在我要考虑向前走一两步。您只询问了如何显示/隐藏撤销/重做,这可以使用我建议的代码来实现。但是您可能正在开发一些绘图应用程序,所以我想您迟早会想要添加项或删除项可撤消/可还原的命令。然后我写的代码就不够了。原因是,如果删除并使用undo/redo重新添加项,则按指针保存项将不再工作。在重新执行删除操作后,指向新重新创建的对象的指针将与先前删除的对应对象的指针不同,因此通过指针保存在HideCommand中的项将无效。

要解决这个无效指针的问题,您需要发明一些其他方法来记录场景中的项目。例如,一些UUID或仅仅是一个整数序列(这就是我要做的),让我们称它为item ID,然后保持这些项目ID和相应指针的双向映射,这样您就可以在那里和后面将ID转换为项指针。

然后,当您通过一些AddItemCommand创建一个项目时,您将创建该项目并生成它的ID,并存储ID和指向映射的指针之间的关系。将此ID的记录放入undo命令中。对于需要引用该项的所有其他命令(例如,HideCommand),您将使用ID而不是指针。这将允许您将所有命令放到堆栈中,使用稳定的ID而不是易失性指针,这些指针可能在撤消/重做、添加或删除对象时发生更改。此外,RemoveItemCommand将记录已删除对象的ID,如果取消,将创建新项(即新的、不同的指针),但使用旧的已知ID。因此引用此ID的其他命令仍然有效。

我希望我能解释清楚。事实上,这并没有那么困难。您只需要理解,如果使用undo/redo添加或删除项,则指针将随着时间的推移而改变,但是ID可以保持不变。为此,需要在命令中而不是指针中保留ID。这当然会改变我写的代码。但我相信,一旦您在应用程序中实现ID <->指针映射,您就可以将它从使用指针调整到使用ID。

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

https://stackoverflow.com/questions/72039002

复制
相关文章

相似问题

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