使用堆栈实现撤消/重做方法 [英] Implementing Undo/Redo methods using Stacks
问题描述
我想使用堆栈(而不是摆动)创建撤消"和重做"按钮.
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 theStudentSaveCommand
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 theundo()
implementation you implement the action to revert thedo()
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
Stack
s 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 andStack
s 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屋!