如何在QT中使用命令模式隐藏QGraphicTiTem中实现撤销功能?
我有一个qgraphicsview
,其中包含一些qgraphicSitem
我有一个功能(hide item),鼠标右键单击,隐藏所需的qgraphicsItem
(retectangle)及其连接的polylines
。我也有一个undo-redo
功能。
撤消 - 它应取消执行最后命令的效果并显示 先前的转换。
重做 - 它将撤消以前的撤消。
要实现此undo-redo
功能,我已经使用了命令模式
。我已经实现了dodo-redo
Zoomin-Zoomout
的功能。
问题是:我不知道如何为hide功能实现撤消redo。意味着要推入堆栈,拉什么?
下面的dum-redo
代码适用于Zoomin-Zoomout
功能。 功能类似
hide
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::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);
}
(仅供
void myView::ZoomIn()
{
double scaleFactor = 1.1;
view->scale(scaleFactor,scaleFactor);
myCommand* command1 = new myCommand(scaleFactor,scene,view);
undoStack->push(command1);
}
。
public:
QUndoStack* undoStack;
我
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* command3 = new myCommand(isRectHiddden,vPtr,GraphName);
undoStack->push(command3);
I am having a QGraphicsView
which contains some QGraphicsItem
I have a feature (Hide Item) which on mouse right click, hide desired QGraphicsItem
(Rectangle) and its connected polylines
. I have a Undo-Redo
feature also.
Undo - It should cancel the effect of last command executed and show
previous transformation.
Redo - It will undo the previous Undo.
To implement this Undo-Redo
feature I have used Command pattern
. I have implemented Undo-Redo
feature for ZoomIn-ZoomOut
.
Question is : I dont know how to implement Undo-Redo for Hide feature. Means what to push into stack, what to pull ?
Below Undo-Redo
code is for ZoomIn-ZoomOut
feature. (It is just for reference that I want to implement Hide
feature something like this. )
myCommand.c
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
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
void myView::ZoomIn()
{
double scaleFactor = 1.1;
view->scale(scaleFactor,scaleFactor);
myCommand* command1 = new myCommand(scaleFactor,scene,view);
undoStack->push(command1);
}
myView.h
public:
QUndoStack* undoStack;
New addition :
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 is :
myCommand* command3 = new myCommand(isRectHiddden,vPtr,GraphName);
undoStack->push(command3);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
考虑到您已经成功实现了Zoom-In/Zoom-Out,这应该非常简单。
所以这很简单。但!!!现在,我要考虑一两个步骤。您只询问显示/隐藏撤消/重做,可以使用我建议的代码来实现。但是您可能正在开发一些绘图应用程序,所以我想您迟早您还需要附加项目或删除信息不可行/可重复的命令。然后,我编写的代码将不够。原因是,如果您删除,则指针持有项目将不再起作用,然后再使用duno/redo再次添加项目。重做删除操作后,新重新创建的对象的指针将不同于您之前已删除的相应对象的指针,因此通过其指针保存在
hidecommand
中的项目将是无效的。为了解决无效指针的问题,您需要发明其他一些记录您现场中有哪些项目的方法。例如,某些UUID或仅一系列整数(这是我要做的),我们称其为项目ID。然后保留这些项目ID和相应指针的双向图,以便您可以将ID转换为项目指针,并在此转换。
然后,当您通过一些
AdditemCommand
创建项目时,您可以创建项目并生成其ID并存储ID与地图指针之间的关系。您将此ID记录放在撤消命令中。对于所有其他需要参考该项目的命令(例如,hidecommand
),您将使用ID代替指针。这将使您将所有命令都放在堆栈中,使用稳定的ID,而不是挥发性指针,这些指针可能会在您撤消/重做对象的添加或删除时会发生变化。另外,removeItemCommand
将记录删除对象的ID,如果撤销,将创建新项目(即新的,不同的指针),但使用旧的已知ID。因此,引用此ID的其他命令仍然有效。我希望我能很好地解释这一点。实际上,这并不困难。您只需要了解,如果您添加或删除使用撤消/重做的项目,则指针会随着时间的推移而变化,但是ID可以保持不变。因此,您需要将ID保留在命令中而不是指针中。当然,这将更改我写的代码。但是我相信,一旦实现ID&lt; - &gt;指针映射在您的应用中。
It should be very simple given the fact that you already successfully implemented zoom-in/zoom-out.
So this is very simple. BUT!!! Now I am going to think one or two steps ahead. You asked only about showing/hiding undo/redo which can be implemented using the code which I suggested. But you are probably developing some drawing app so I guess that sooner or later you will want also add-item or remove-item undoable/redoable commands. And then the code which I wrote will not suffice any more. The reason is that holding item by pointer will not work any more if you remove and then add again the item using undo/redo. After redoing of remove operation, the pointer to the newly re-created object will be different the the pointer to the corresponding object which you had deleted earlier, so the item kept in
HideCommand
via its pointer will be invalid.To solve this problem of invalid pointers, you need to invent some other way of recording what items you have in your scene. For example some UUID or just a sequence of integers (which is what I would do), lets call it item ID. And then keep a two-way map of these item IDs and corresponding pointers, so that you are able to translate ID to the item pointer, there and back.
Then when you create an item via some
AddItemCommand
you create the item and generate its ID and store the relation between the ID and the pointer to the map. You put record of this ID in the undo command. And for all other commands which will need to refer to that item (e.g. thatHideCommand
) you will use the ID instead of the pointer. This will allow you put all commands to the stack, use stable IDs and not volatile pointers which may change as you undo/redo adding or deleting of objects. AlsoRemoveItemCommand
will record the ID of the removed object and if undone, the new item will be created (i.e. a new, different pointer) but with the old, known ID. So other commands referencing this ID will still be valid.I hope I managed to explain this well. In fact it is not that difficult. You just need to understand that pointers will change over time if you add or remove items with undo/redo, but IDs can stay the same. Therefor you need to keep IDs in your commands and not pointers. This will of course change the code which I wrote a bit. But I believe you are able to adjust it from using pointers to using IDs by yourself once you implement the ID <-> pointer mapping in your app.