Swing 的 undo 包实现撤销/重做功能
0 Edit
与Command模式中的Command类似的一个概念。Command模式将操作的执行逻辑封装到一个个Command对象中,解耦了操作发起者和操作执行逻辑之间的耦合关系:操作发起者要进行一个操作,不用关心具体的执行逻辑,只需创建一个相应的Command实例,调用它的执行接口即可。
而在swing中,与界面交互的各种操作,比如插入,删除等被称之为Edit,实际上就是Command。
1 undo包
1.1 UndoableEdit接口
一个已完成的编辑操作(edit),一个可以被Undo/Redo的操作。
1.2 AbstractUndoableEdit
实现UndoableEdit。
1.3 CompoundEdit
- 如果此编辑从未收到end
- UndoableEdit撤消/恢复的集合,集体通过这一CompoundEdit
- undo
发送undo所有包含UndoableEdits在它们被添加的顺序相反
1.4 UndoManager
负责实现 redo/undo。
各种UndoableEdit实例通过
addEdit
加入UndoManager
public synchronized boolean addEdit(UndoableEdit anEdit) { boolean retVal; // 从indexOfNextAdd到末尾进行修剪去尾,因为一旦新的操作被添加,我们永远无法访问到这些编辑 trimEdits(indexOfNextAdd, edits.size()-1); retVal = super.addEdit(anEdit); if (inProgress) { retVal = true; } // 也许父类添加了此编辑,但也可能没有添加(也许正在进行的复合编辑(compound edit)代替了它。或者也许此UndoManager不再进行了)。因此,请确保indexOfNextAdd指向正确的位置。 indexOfNextAdd = edits.size(); // 加强限制 trimForLimit(); return retVal; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
通过调用UndoManager的
undo
撤消适当的编辑。如果已调用end,则此方法将调用父类方法,否则将调用undo对下一个编辑的索引和上一个显著编辑之间的所有编辑,适当地更新下一个编辑的索引
redo
方法来实现Undo/Redo功能。
这里提一下如下两个方法:
- getUndoPresentationName()
返回此编辑可撤消形式的描述。 如果end已调用此电话为超。 否则,如果有编辑撤消,这将返回从下一个显著编辑将被撤销的价值。 如果没有编辑可以撤销, end并没有被调用这个返回从值UIManager财产“AbstractUndoableEdit.undoText”
和 - getRedoPresentationName()
返回此编辑可重复执行形式的说明。 如果end已调用此电话为超。 否则,如果有编辑重做,这种回报从下一个显著的编辑将要恢复的价值。 如果没有编辑重做和end尚未援引这一收益来自值UIManager财产“AbstractUndoableEdit.redoText”
可以为Undo/Redo操作提供描述。比如,如果要在菜单中提供“撤消删除”,“重做删除”菜单项而不是简单的无所指的“撤消”,“重做”菜单项,可以通过这两个方法来获得。
2 使用undo包
1、创建UndoManager实例;
2、创建各种实现UndoableEdit的具体操作类;
3、调用某种操作时,创建一个具体操作类的实例,加入UndoManager;
4、在Undo/Redo时,直接调用UndoManager的undo/redo方法。
3 实例
产品列表用一个JList实现
3.1 创建UndoManager实例
SamplePanel是我们的产品列表界面实现类,因此我们在SamplePanel类的初始化中加入:
3.2 创建各种实现UndoableEdit的具体操作类
定义添加,删除,上移,下移的具体操作类。
AddEdit类负责添加操作;
DeleteEdit类负责删除操作;
UpDownEdit类负责上移和下移操作。
- MVC架构中,JList是一个View类,操作内部数据的能力来自于它的数据模型类ListModel
推荐阅读:Java中的JList和DefaultListModel的亲密关系
ListEdit抽象类
含有一个ListModel成员,供其他具体操作类继承。
下面分别实现AddEdit,DeleteEdit,UpDownEdit类,它们均继承自ListEdit类。
在execute方法中实现操作逻辑,在undo方法中实现Undo的逻辑。redo方法在ListEdit中已经实现
一个需要注意的问题是,在实现执行逻辑时要保留现场数据,以供Undo时恢复现场。
比如,要执行Delete操作,我们要记住删除的元素和所在位置这两个现场数据,undo方法据此来在原位置插入被删除的元素。如果没有这两个现场数据,undo就无从下手了。
DeleteEdit类
其他操作类的实现原理基本类似,这里不再赘述。
package com.javaedge;
import javax.swing.DefaultListModel;
import javax.swing.undo.CannotUndoException;
/*
* DeleteEdit 删除操作
*/
public class DeleteEdit extends ListEdit { // 被删除的元素 private Object element; // 删除发生的位置 private int index; public DeleteEdit(DefaultListModel model, int index) { this.model = model; this.index = index; } public void execute() { element = model.getElementAt(index); if (element != null) { model.removeElementAt(index); } } public void undo() throws CannotUndoException { if (element != null) { model.insertElementAt(element, index); } } public String getUndoPresentationName() { return "撤消删除元素"; } public String getRedoPresentationName() { return "重做删除元素"; }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
3 在界面中调用添加,删除,上移,下移操作
以添加操作为例,在“添加”按钮的事件处理器中:
1、 准备好AddEdit所需的参数(这里除了ListModel外,还需要一个元素名称,通过弹出输入框来获取);
2、 创建AddEdit实例,调用其execute方法;
3、 将AddEdit实例加入UndoManager。
addButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { String s=JOptionPane.showInputDialog(null,"请输入条目:","添加",JOptionPane.PLAIN_MESSAGE); if(s!=null&&!s.equals("")){ AddEdit edit=new AddEdit(model,s); edit.execute(); undoManager.addEdit(edit); } } });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
其他调用操作见SamplePanel类中的相应代码,不再一一列出。
4 调用Undo/Redo
在“撤消”按钮的事件处理器中,直接调用UndoManager的undo方法;
在“重做”按钮的事件处理器中,直接调用UndoManager的redo方法。
SampleFrame.java 示例的启动类
SamplePanel.java 产品列表界面类
ListEdit.java 列表操作抽象类
AddEdit.java 添加操作类
DeleteEdit.java 删除操作类
UpDownEdit.java 上移/下移操作类
文章来源: javaedge.blog.csdn.net,作者:JavaEdge.,版权归原作者所有,如需转载,请联系作者。
原文链接:javaedge.blog.csdn.net/article/details/106207945
- 点赞
- 收藏
- 关注作者
评论(0)