我正在使用Java Swing制作一个文本编辑器,使用的组件是JTextArea。我想知道如何在JTextArea中实现撤销 (Undo) 和重做 (Redo) 功能,因为我目前无法使用它们。
javax.swing
中存在一个Undo Manager,你可以将其连接到JTextArea的更改事件上。UndoManager manager = new UndoManager();
textArea.getDocument().addUndoableEditListener(manager);
一旦将管理器附加到JTextArea文档上,它将监视文本区域内容的所有更改。
在将管理器附加到文本组件之后,您必须提供某些手段告诉管理器撤消/重做操作。
在需要的地方(例如actionlistener的actionPerformed()方法)调用UndoManager的public void undo()和public void redo()方法。
您可以通过以下方式将Action对象附加到按钮,而不是调用undo()和redo()方法,从而简化任务:
JButton undoButton = new JButton(UndoManagerHelper.getUndoAction(manager));
JButton redoButton = new JButton(UndoManagerHelper.getRedoAction(manager));
UndoManagerHelper
类是用户自定义的吗?我在Eclipse中没有得到它的自动完成。我也搜索了Oracle Java文档,但无法找到该类。我正在使用Java 8。 - Omkar76我已经有一段时间没有做这件事了,也不记得细节,但这里有一个链接提供一些信息:http://java.sun.com/docs/books/tutorial/uiswing/components/generaltext.html
向下滚动到标题为“监听文档更改”的部分开始学习。
我创建了一个简单的类,可以通过一个方法调用为JTextcomponent(JTextField、JTextArea等)分配撤消功能:
UndoTool.addUndoFunctionality(area);
或者,您可以使用预先分配了撤销功能的新JTextArea:
UndoTool.createJTextFieldWithUndo();
public class UndoTool {
private static final String REDO_KEY = "redo";
private static final String UNDO_KEY = "undo";
private JTextComponent component;
private KeyStroke undo = KeyStroke.getKeyStroke("control Z");
private KeyStroke redo = KeyStroke.getKeyStroke("control Y");
public UndoTool(JTextComponent component) {
this.component = component;
}
public void setUndo(KeyStroke undo) {
this.undo = undo;
}
public void setRedo(KeyStroke redo) {
this.redo = redo;
}
public static void addUndoFunctionality(JTextComponent component) {
UndoTool tool = new UndoTool(component);
UndoManager undo = tool.createAndBindUndoManager();
tool.bindUndo(undo);
tool.bindRedo(undo);
}
public static JTextArea createJTextAreaWithUndo() {
JTextArea area = new JTextArea();
addUndoFunctionality(area);
return area;
}
public static JTextField createJTextFieldWithUndo() {
JTextField field = new JTextField();
addUndoFunctionality(field);
return field;
}
public UndoManager createAndBindUndoManager() {
Check.notNull(component);
UndoManager manager = new UndoManager();
Document document = component.getDocument();
document.addUndoableEditListener(event -> manager.addEdit(event.getEdit()));
return manager;
}
public void bindRedo(UndoManager manager) {
component.getActionMap().put(REDO_KEY, new AbstractAction(REDO_KEY) {
@Override
public void actionPerformed(ActionEvent evt) {
try {
if (manager.canRedo()) {
manager.redo();
}
} catch (CannotRedoException ignore) {
}
}
});
component.getInputMap().put(redo, REDO_KEY);
}
public void bindUndo(UndoManager manager) {
component.getActionMap().put(UNDO_KEY, new AbstractAction(UNDO_KEY) {
@Override
public void actionPerformed(ActionEvent evt) {
try {
if (manager.canUndo()) {
manager.undo();
}
} catch (CannotUndoException ignore) {
}
}
});
component.getInputMap().put(undo, UNDO_KEY);
}
}
我不得不浏览多个链接才能获得足够的帮助。我在这里添加了我成功实现的内容,以帮助未来的访问者。我使用JTextPane实现了这个功能,但是我认为对于JTextArea也适用。
JTextArea textArea = new JTextArea();
JButton undo = new JButton("Undo");
JButton redo = new JButton("Redo");
KeyStroke undoKeyStroke = KeyStroke.getKeyStroke(
KeyEvent.VK_Z, Event.CTRL_MASK);
KeyStroke redoKeyStroke = KeyStroke.getKeyStroke(
KeyEvent.VK_Y, Event.CTRL_MASK);
UndoManager undoManager = new UndoManager();
Document document = textArea.getDocument();
document.addUndoableEditListener(new UndoableEditListener() {
@Override
public void undoableEditHappened(UndoableEditEvent e) {
undoManager.addEdit(e.getEdit());
}
});
// Add ActionListeners
undo.addActionListener((ActionEvent e) -> {
try {
undoManager.undo();
} catch (CannotUndoException cue) {}
});
redo.addActionListener((ActionEvent e) -> {
try {
undoManager.redo();
} catch (CannotRedoException cre) {}
});
// Map undo action
textArea.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(undoKeyStroke, "undoKeyStroke");
textArea.getActionMap().put("undoKeyStroke", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
try {
undoManager.undo();
} catch (CannotUndoException cue) {}
}
});
// Map redo action
textArea.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(redoKeyStroke, "redoKeyStroke");
textArea.getActionMap().put("redoKeyStroke", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
try {
undoManager.redo();
} catch (CannotRedoException cre) {}
}
});