使用堆栈实现撤消/重做方法 [英] Implementing Undo/Redo methods using Stacks

查看:65
本文介绍了使用堆栈实现撤消/重做方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to create "undo" and "redo" buttons using stacks (not swing).

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

When "undo" is clicked, Textfields, Lists and everything need to be undone/redone. I know I have to use pop, push, etc. But what do I put in the stacks? Textfield values? List contents?

示例:

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

    如何重置这些?

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

    And is there a way to just stock the current state of the project's data in the stack?

    推荐答案

    希望我没看错,因为我不太明白您所说的使用堆栈(而不是摆动)"是什么意思.Stack 是一种数据结构,Swing 是一种 UI 框架.所以这些基本上没有任何关系.

    Hopefully, I got you right, since I do not really understand what you mean by "using stacks (not swing)". A Stack is a data structure and Swing is a UI framework. So those have basically nothing to do with each other.

    执行撤消/重做通常是通过使用以下方法之一来完成的.您应该使用哪一种取决于您想要的撤消/重做行为.

    Implementing undo/redo is typically done by using one of the following approaches. Which one you should use depends on your desired undo/redo behavior.

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

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

    Implementing this approach would look something like this:

    public interface ICommand {
        void do();
        void undo();
    }
    
    public class StudentSaveCommand implements ICommand {
    
        public StudentSaveCommand(Student student) { ... }
        [...]
    }
    

    StudentSaveCommand 类的 do() 实现中,您实现了实际保存给定学生应该采取的操作,例如将数据插入数据库、保存到文件或简单地将其添加到列表中.在 undo() 实现中,您实现了恢复 do() 实现的操作,例如从数据库中删除、删除文件或将其从列表中删除.

    In the do() implementation of the StudentSaveCommand class you implement the action which should be taken to actually save the given student, e.g. inserting the data into the database, saving to a file or simply adding it to a list. In the undo() implementation you implement the action to revert the do() implementation, e.g. deleting from the database, deleting the file or removing it from the list.

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

    To finally implement the undo/redo feature using Stacks you would do something like this:

    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 中,我将实现/使用某种数据绑定.如您所见,这种方法不适用于在非常细粒度的级别上实现撤消/重做,例如在文本框中更改学生的姓名.这是第二种方法.

    To easily reflect the changes on your model to your GUI I would implement/use some sort of data binding. As you can see, this approach is not that appropriate to implement undo/redo on a very fine-grained level, e.g. changing a student's name in a textbox. Here comes the second approach into play.

    使用备忘录模式撤消/重做.

    Undo/redo using Memento Pattern.

    使用此模式可以保存和恢复对象的状态,例如学生.使用此模式和 Stack 实现撤消/重做功能的代码可能如下所示:

    Using this pattern allows you to save and restore states of an object, e.g. a Student. The implementation for an undo/redo feature using this pattern and Stacks the code would probably look something like this:

    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 对象所做的更改,我也更喜欢数据绑定或实现如下所示的方法,该方法必须在撤消/重做操作后调用:

    To reflect the changes which were made to the Student object I also would prefer data binding or implement a method like the following which must be called after an undo/redo action:

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

    <小时>

    要在您的撤消/重做实现中兼具这两种方法的优点,您还可以将它们结合起来.但是,最佳方法在很大程度上取决于规范,分别取决于您真正想要实现的目标.


    To have the advantages of both approaches in your undo/redo implementation you also can combine those. However, the best approach depends strongly on the specification, respectively what you really want to achieve.

    这篇关于使用堆栈实现撤消/重做方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆