使用Stacks实现Undo / Redo方法

时间:2016-11-02 22:58:58

标签: java stack undo-redo

我想创建"撤消"和"重做"使用堆栈的按钮(不是摆动)。

当"撤消"单击,文本字段,列表和所有内容都需要撤消/重做。我知道我必须使用pop,push等。但是我在堆栈中放了什么? Textfield值?列出内容?

示例:

  • 我在学校注册了一名学生。
    • 文本字段中的学生信息已更改
    • 学生列表包含新学生

如何重置这些?

有没有办法在库中存储项目数据的当前状态?

1 个答案:

答案 0 :(得分:2)

希望我能帮到你,因为我并不真正明白你的意思"使用堆栈(不是摆动)"。 Stack是数据结构, Swing 是UI框架。所以那些基本上没有任何关系。

通常使用以下方法之一来实现撤消/重做。您应该使用哪一个取决于您所需的撤消/重做行为。

  

使用命令模式撤消/重做。

实现这种方法看起来像这样:

public interface ICommand {
    void do();
    void undo();
}

public class StudentSaveCommand implements ICommand {

    public StudentSaveCommand(Student student) { ... }
    [...]
}

do()课程的StudentSaveCommand实施中,您实施了应该用来实际保存给定学生的操作,例如将数据插入数据库,保存到文件或只是将其添加到列表中。 在undo()实施中,您实施了还原do()实施的操作,例如从数据库中删除,删除文件或从列表中删除它。

要使用Stack最终实现撤消/重做功能,您可以执行以下操作:

public void btnSaveStudentClickHandler() {
    ICommand c = new IStudentSaveCommand(theStudentFromGUI);
    c.do();
    _redoStack.clear();
    _undoStack.push(c);
}

public void btnUndoClickHandler() {
    ICommand undoCommand = _undoStack.pop();
    undoCommand.undo();
    _redoStack.push(undoCommand); 
}

public void btnRedoClickHandler() {
    ICommand redoCommand = _redoStack.pop();
    redoCommand.do();
    _undoStack.push(redoCommand);
}

为了轻松地将模型上的更改反映到GUI,我将实现/使用某种数据绑定。正如您所看到的,这种方法不适合在非常细粒度的级别上实现撤消/重做,例如在文本框中更改学生的姓名。这是第二种方法。

  

使用 Memento Pattern 撤消/重做。

使用此模式可以保存和恢复对象的状态,例如一个Student。使用此模式和Stack代码的撤消/重做功能的实现可能看起来像这样:

public void txtStudentNameLostFocusHandler() {
    Memento sm = student.getSavedState();
    _redoStack.clear();
    _undoStack.push(sm);
}

public void btnUndoClickHandler() {
    Memento m = _undoStack.pop();
    student.restoreSavedState(m);
    _redoStack.push(m);
}

// [...] Redo implementation straight-forward

为了反映对Student对象所做的更改,我更喜欢数据绑定或实现类似下面的方法,必须在撤消/重做操作后调用:

public void updateStudentGUI(Student student) {
    txtName.setText(student.getName());
    [...]
}

要在撤消/重做实现中获得这两种方法的优点,您也可以将这些方法结合起来。但是,最好的方法很大程度上取决于规范,分别取决于您真正想要实现的目标。