如何在java中为动作实现简单的撤消/重做?

Che*_*ian 12 java user-interface undo command-pattern

我已经创建了一个XML编辑器,我在最后阶段陷入困境:添加撤消/重做功能.

当用户向JTree添加元素,属性或文本时,我只需要添加undo/redo.

我现在仍然很新,但今天在学校我试图(不成功)创建两个栈对象[],称为撤消和重做,并添加执行的动作.

例如,我有:

Action AddElement() {

// some code
public void actionPerformed(ActionEvent e) {

                    performElementAction();
                }
}
Run Code Online (Sandbox Code Playgroud)

performElementAction实际上只是向JTree添加了一个Element.

我想添加一种方法来将此操作添加到我的撤消堆栈中.是否只有一种简单的方法来实现undo.push(执行整个动作)或其他什么?

抱歉听起来像坏人,但那就是我:(

Men*_*ris 8

TL; DR:您可以通过实现Command和Memento模式(Design Patterns - Gama et.al)来支持撤消和重做操作.

纪念品模式

这种简单的模式允许您保存对象的状态.只需将对象包装在一个新类中,并在其状态发生变化时更新它.

public class Memento
{
    MyObject myObject;

    public MyObject getState()
    {
        return myObject;
    }

    public void setState(MyObject myObject)
    {
        this.myObject = myObject;
    }
}
Run Code Online (Sandbox Code Playgroud)

命令模式

Command模式存储原始对象(我们想要支持undo/redo)和memento对象,在撤消的情况下我们需要它.此外,还定义了两种方法:

  1. execute:执行命令
  2. unExecute:删除命令

码:

public abstract class Command
{
    MyObject myObject;
    Memento memento;

    public abstract void execute();

    public abstract void unExecute();
}
Run Code Online (Sandbox Code Playgroud)

定义扩展Command的逻辑"Actions"(例如Insert):

public class InsertCharacterCommand extends Command
{
    //members..

    public InsertCharacterCommand()
    {
        //instantiate 
    }

    @Override public void execute()
    {
        //create Memento before executing
        //set new state
    }

    @Override public void unExecute()
    {
        this.myObject = memento.getState()l
    }
}
Run Code Online (Sandbox Code Playgroud)

应用模式:

最后一步定义了撤消/重做行为.它们的核心思想是存储一堆命令,这些命令用作命令的历史列表.要支持重做,只要应用撤消命令,就可以保留辅助指针.请注意,无论何时插入新对象,都会删除其当前位置之后的所有命令; 通过以下deleteElementsAfterPointer定义的方法实现:

private int undoRedoPointer = -1;
private Stack<Command> commandStack = new Stack<>();

private void insertCommand()
{
    deleteElementsAfterPointer(undoRedoPointer);
    Command command =
            new InsertCharacterCommand();
    command.execute();
    commandStack.push(command);
    undoRedoPointer++;
}

private void deleteElementsAfterPointer(int undoRedoPointer)
{
    if(commandStack.size()<1)return;
    for(int i = commandStack.size()-1; i > undoRedoPointer; i--)
    {
        commandStack.remove(i);
    }
}

 private void undo()
{
    Command command = commandStack.get(undoRedoPointer);
    command.unExecute();
    undoRedoPointer--;
}

private void redo()
{
    if(undoRedoPointer == commandStack.size() - 1)
        return;
    undoRedoPointer++;
    Command command = commandStack.get(undoRedoPointer);
    command.execute();
}
Run Code Online (Sandbox Code Playgroud)

结论:

是什么让这个设计强大的是,你可以(通过扩展,只要你喜欢添加许多命令的事实Command类),例如RemoveCommand,UpdateCommand等等.此外,相同的模式适用于任何类型的对象,使得设计可以在不同的用例中重复使用修改.


Ósc*_*pez 7

看看命令模式,其用途包括实现撤消/重做功能.


nol*_*egs 0

我会尝试创建一个 Action 类,其中 AddElementAction 类继承 Action。AddElementAction 可以有一个 Do() 和 Undo() 方法,可以相应地添加/删除元素。然后,您可以保留两堆用于撤消/重做的操作,只需在弹出顶部元素之前调用 Do()/Undo() 即可。