【发布时间】:2010-03-30 17:55:13
【问题描述】:
我正在使用 Java swing 制作文本编辑器。我也在使用 JTextArea。我想知道如何在 JTextArea 中使用 Undo 和 Redo 功能,因为我无法使用它。
【问题讨论】:
我正在使用 Java swing 制作文本编辑器。我也在使用 JTextArea。我想知道如何在 JTextArea 中使用 Undo 和 Redo 功能,因为我无法使用它。
【问题讨论】:
据我了解,JTextArea 没有内置的固有撤消/重做功能,但Google search 确实找到了this article,这可能会有所帮助。
javax.swing 中显然存在一个Undo Manager,您可以将其连接到 JTextArea 的更改事件。
【讨论】:
你可以这样做
UndoManager manager = new UndoManager();
textArea.getDocument().addUndoableEditListener(manager);
一旦管理器附加到 JTextArea 的文档中,它将监视所有更改 到文本区域的内容。
将管理器附加到文本组件后,您必须提供一些方法来告诉 经理撤消/重做操作。
在必要时调用 UndoManager 的 public void undo() 和 public void redo() 方法(例如 actionlistener 的 actionPerformed() 方法)
您可以通过以下方式将 Action 对象附加到按钮上,而不是调用简化任务的 undo() 和 redo() 方法:
JButton undoButton = new JButton(UndoManagerHelper.getUndoAction(manager));
JButton redoButton = new JButton(UndoManagerHelper.getRedoAction(manager));
【讨论】:
UndoManagerHelper 类用户定义的吗?我没有在 Eclipse 中自动完成它。我还搜索了 oracle java 文档,但找不到该类。我正在使用 java 8
我已经有一段时间没有这样做了,我不记得细节了,但这里有一个包含一些信息的链接:http://java.sun.com/docs/books/tutorial/uiswing/components/generaltext.html
向下滚动到标题为“侦听文档更改”的部分以开始使用。
【讨论】:
我必须通过多个链接才能获得足够的帮助。我在这里添加我成功实施的内容,只是为了帮助未来的访问者。我使用 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) {}
}
});
【讨论】:
我创建了一个简单的类,它可以通过单个方法调用将撤消功能分配给 JText 组件(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);
}
}
【讨论】: