Java/Swing JFC/Undo Redo
Содержание
- 1 Adding Undo and Redo to a Text Component
- 2 Add Undo and Redo to a text component
- 3 Add undo support to the StyleFrame example
- 4 An example that shows lots of little UndoManager details
- 5 A sample app showing the use of UndoableToggleEdit and CompoundEdit
- 6 Bind the undo action to ctl-Z
- 7 Create an undo action and add it to the text component
- 8 Create a redo action and add it to the text component (JTextComponent)
- 9 Creating TextArea with Undo, Redo Capabilities
- 10 Listen for undo and redo events
- 11 Simple GUI demo of UndoManager and friends
- 12 The use of StateEdit(able)
- 13 The use of UndoableToggleEdit
- 14 The use of UndoManager
- 15 Undoable Drawing Panel 2
- 16 Undo Drawing
- 17 Undo Example 1
- 18 Undo Example 2
- 19 Undo Example 3
- 20 Undo Example 4
- 21 Undo Example 5
- 22 Undo Example 6
- 23 Undo Example 7
- 24 Undo manager
- 25 Undo redo textarea
Adding Undo and Redo to a Text Component
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class Main{
public static void main(String[] argv) throws Exception{
JTextComponent textcomp = new JTextArea();
final UndoManager undo = new UndoManager();
Document doc = textcomp.getDocument();
JFrame f = new JFrame();
f.add(new JScrollPane(textcomp));
f.setSize(330,300);
f.setVisible(true);
doc.addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undo.addEdit(evt.getEdit());
}
});
textcomp.getActionMap().put("Undo",
new AbstractAction("Undo") {
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canUndo()) {
undo.undo();
}
} catch (CannotUndoException e) {
}
}
});
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
textcomp.getActionMap().put("Redo",
new AbstractAction("Redo") {
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canRedo()) {
undo.redo();
}
} catch (CannotRedoException e) {
}
}
});
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");
}}
Add Undo and Redo to a text component
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class Main {
public static void main(String[] argv) throws Exception {
JTextComponent textcomp = new JTextArea();
final UndoManager undo = new UndoManager();
Document doc = textcomp.getDocument();
doc.addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undo.addEdit(evt.getEdit());
}
});
textcomp.getActionMap().put("Undo", new AbstractAction("Undo") {
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canUndo()) {
undo.undo();
}
} catch (CannotUndoException e) {
}
}
});
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
textcomp.getActionMap().put("Redo", new AbstractAction("Redo") {
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canRedo()) {
undo.redo();
}
} catch (CannotRedoException e) {
}
}
});
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");
}
}
Add undo support to the StyleFrame example
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// UndoStyleFrame.java
//Add undo support to the StyleFrame example. This example only
//retains the most recent edit, to keep things simple.
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.SwingConstants;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.undo.UndoableEdit;
public class UndoStyleFrame extends StyleFrame {
protected UndoAct undoAction = new UndoAct(); // an Action for undo
protected RedoAct redoAction = new RedoAct(); // an Action for redo
public UndoStyleFrame() {
super();
setTitle("UndoStyleFrame");
// register the Actions as undo listeners (we inherited textPane)
textPane.getDocument().addUndoableEditListener(undoAction);
textPane.getDocument().addUndoableEditListener(redoAction);
// create menu for undo/redo
JMenu editMenu = new JMenu("Edit");
editMenu.add(new JMenuItem(undoAction));
editMenu.add(new JMenuItem(redoAction));
menuBar.add(editMenu); // we inherited menuBar from superclass
// create buttons for undo/redo
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton(undoAction));
buttonPanel.add(new JButton(redoAction));
getContentPane().add(buttonPanel, java.awt.BorderLayout.SOUTH);
}
// begin inner classes ------------
public class UndoAct extends AbstractAction implements UndoableEditListener {
private UndoableEdit edit;
public UndoAct() {
super("Undo");
setEnabled(false);
}
public void updateEnabled() {
setEnabled(edit.canUndo());
}
public void undoableEditHappened(UndoableEditEvent event) {
edit = event.getEdit();
putValue(NAME, edit.getUndoPresentationName());
updateEnabled();
}
public void actionPerformed(ActionEvent ae) {
edit.undo();
updateEnabled(); // disable undo
redoAction.updateEnabled(); // enable redo
}
}
public class RedoAct extends AbstractAction implements UndoableEditListener {
private UndoableEdit edit;
public RedoAct() {
super("Redo");
setEnabled(false);
}
public void updateEnabled() {
setEnabled(edit.canRedo());
}
public void undoableEditHappened(UndoableEditEvent event) {
edit = event.getEdit();
putValue(NAME, edit.getRedoPresentationName());
updateEnabled();
}
public void actionPerformed(ActionEvent ae) {
edit.redo();
updateEnabled(); // disable redo
undoAction.updateEnabled(); // enable undo
}
}
// end inner classes ------------
public static void main(String[] args) {
JFrame frame = new UndoStyleFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
//StyleFrame.java
//A JTextPane with a menu for Style manipulation.
class StyleFrame extends JFrame implements ActionListener {
protected StyleBox styleBox;
protected JTextPane textPane;
protected JMenuBar menuBar;
protected JMenu applyStyleMenu, modifyStyleMenu;
protected JMenuItem createItem;
public StyleFrame() {
super("StyleFrame");
styleBox = new StyleBox();
textPane = new JTextPane();
getContentPane().add(new JScrollPane(textPane), BorderLayout.CENTER);
// set up menu
menuBar = new JMenuBar();
JMenu styleMenu = new JMenu("Style");
menuBar.add(styleMenu);
setJMenuBar(menuBar);
applyStyleMenu = new JMenu("Set Logical Style");
applyStyleMenu
.setToolTipText("set the Logical Style for the paragraph at caret location");
styleMenu.add(applyStyleMenu);
modifyStyleMenu = new JMenu("Modify Style");
modifyStyleMenu
.setToolTipText("redefine a named Style (will affect paragraphs using that style)");
styleMenu.add(modifyStyleMenu);
createItem = new JMenuItem("Create New Style");
createItem
.setToolTipText("define a new Style (which can then be applied to paragraphs)");
createItem.addActionListener(this);
styleMenu.add(createItem);
// add the default style to applyStyleMenu and modifyStyleMenu
createMenuItems(StyleContext.DEFAULT_STYLE);
}
protected void createMenuItems(String styleName) {
// add "styleName" to applyStyleMenu and modifyStyleMenu
JMenuItem applyItem = new JMenuItem(styleName);
applyItem.addActionListener(this);
applyStyleMenu.add(applyItem);
JMenuItem modifyItem = new JMenuItem(styleName);
modifyItem.addActionListener(this);
modifyStyleMenu.add(modifyItem);
}
public void actionPerformed(ActionEvent e) {
// determine which menuItem was invoked and process it
JMenuItem source = (JMenuItem) e.getSource();
if (applyStyleMenu.isMenuComponent(source)) {
// apply an existing style to the paragraph at the caret position
String styleName = source.getActionCommand();
Style style = textPane.getStyle(styleName);
textPane.setLogicalStyle(style);
}
if (source == createItem) {
// define a new Style and add it to the menus
styleBox.clear();
int response = JOptionPane.showConfirmDialog(this, styleBox,
"Style Editor", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
if (response == JOptionPane.OK_OPTION
&& styleBox.getStyleName().length() > 0) {
String styleName = styleBox.getStyleName();
Style style = textPane.addStyle(styleName, null);
styleBox.fillStyle(style);
createMenuItems(styleName); // add new Style to the menus
}
}
if (modifyStyleMenu.isMenuComponent(source)) {
// redefine a Style (will automatically redraw paragraphs using
// Style)
String styleName = source.getActionCommand();
Style style = textPane.getStyle(styleName);
styleBox.loadFromStyle(style);
int response = JOptionPane.showConfirmDialog(this, styleBox,
"Style Editor", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
if (response == JOptionPane.OK_OPTION)
styleBox.fillStyle(style);
}
}
public static void main(String[] args) {
JFrame frame = new StyleFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
//StyleBox.java
//A control panel that can be used to edit a style"s paragraph attributes.
class StyleBox extends JPanel {
private static final String[] fonts = { "Monospaced", "Serif", "SansSerif" };
private static final String[] sizes = { "8", "10", "12", "18", "24", "36" };
private JTextField nameField;
private JComboBox fontCombo, sizeCombo;
private JTextField leftField, rightField, aboveField, belowField;
private JCheckBox boldCheck, italicCheck;
public StyleBox() {
// create the fields and lay them out
super(new BorderLayout(4, 4));
JPanel labelPanel = new JPanel(new GridLayout(8, 1, 0, 2));
JPanel valuePanel = new JPanel(new GridLayout(8, 1, 0, 2));
add(labelPanel, BorderLayout.WEST);
add(valuePanel, BorderLayout.CENTER);
JLabel lab;
JPanel sidePanel;
lab = new JLabel("Style Name", SwingConstants.RIGHT);
labelPanel.add(lab);
nameField = new JTextField();
lab.setLabelFor(nameField);
valuePanel.add(nameField);
lab = new JLabel("Font", SwingConstants.RIGHT);
labelPanel.add(lab);
fontCombo = new JComboBox(fonts);
fontCombo.setEditable(true); // user may enter custom value
lab.setLabelFor(fontCombo);
valuePanel.add(fontCombo);
lab = new JLabel("Size", SwingConstants.RIGHT);
labelPanel.add(lab);
sizeCombo = new JComboBox(sizes);
sizeCombo.setEditable(true); // user may enter custom value
lab.setLabelFor(sizeCombo);
sidePanel = new JPanel(new BorderLayout(4, 0));
sidePanel.add(sizeCombo, BorderLayout.CENTER);
sidePanel.add(new JLabel("points"), BorderLayout.EAST);
valuePanel.add(sidePanel);
lab = new JLabel("Left Indent", SwingConstants.RIGHT);
labelPanel.add(lab);
leftField = new JTextField();
lab.setLabelFor(leftField);
sidePanel = new JPanel(new BorderLayout(4, 0));
sidePanel.add(leftField, BorderLayout.CENTER);
sidePanel.add(new JLabel("points"), BorderLayout.EAST);
valuePanel.add(sidePanel);
lab = new JLabel("Right Indent", SwingConstants.RIGHT);
labelPanel.add(lab);
rightField = new JTextField();
lab.setLabelFor(rightField);
sidePanel = new JPanel(new BorderLayout(4, 0));
sidePanel.add(rightField, BorderLayout.CENTER);
sidePanel.add(new JLabel("points"), BorderLayout.EAST);
valuePanel.add(sidePanel);
lab = new JLabel("Space Above", SwingConstants.RIGHT);
labelPanel.add(lab);
aboveField = new JTextField();
lab.setLabelFor(aboveField);
sidePanel = new JPanel(new BorderLayout(4, 0));
sidePanel.add(aboveField, BorderLayout.CENTER);
sidePanel.add(new JLabel("points"), BorderLayout.EAST);
valuePanel.add(sidePanel);
lab = new JLabel("Space Below", SwingConstants.RIGHT);
labelPanel.add(lab);
belowField = new JTextField();
lab.setLabelFor(belowField);
sidePanel = new JPanel(new BorderLayout(4, 0));
sidePanel.add(belowField, BorderLayout.CENTER);
sidePanel.add(new JLabel("points"), BorderLayout.EAST);
valuePanel.add(sidePanel);
boldCheck = new JCheckBox("Bold");
italicCheck = new JCheckBox("Italic");
sidePanel = new JPanel(new GridLayout(1, 2));
sidePanel.add(boldCheck);
sidePanel.add(italicCheck);
valuePanel.add(sidePanel);
clear(); // sets initial values, etc.
}
public void clear() {
// reset all fields (also sets nameField to be editable)
nameField.setText("");
nameField.setEditable(true);
fontCombo.setSelectedIndex(0);
sizeCombo.setSelectedIndex(2);
leftField.setText("0.0");
rightField.setText("0.0");
aboveField.setText("0.0");
belowField.setText("0.0");
boldCheck.setSelected(false);
italicCheck.setSelected(false);
}
public String getStyleName() {
// return the name of the style
String name = nameField.getText();
if (name.length() > 0)
return name;
else
return null;
}
public void fillStyle(Style style) {
// mutate "style" with the values entered in the fields
// (no value checking--could throw NumberFormatException)
String font = (String) fontCombo.getSelectedItem();
StyleConstants.setFontFamily(style, font);
String size = (String) sizeCombo.getSelectedItem();
StyleConstants.setFontSize(style, Integer.parseInt(size));
String left = leftField.getText();
StyleConstants.setLeftIndent(style, Float.valueOf(left).floatValue());
String right = rightField.getText();
StyleConstants.setRightIndent(style, Float.valueOf(right).floatValue());
String above = aboveField.getText();
StyleConstants.setSpaceAbove(style, Float.valueOf(above).floatValue());
String below = belowField.getText();
StyleConstants.setSpaceBelow(style, Float.valueOf(below).floatValue());
boolean bold = boldCheck.isSelected();
StyleConstants.setBold(style, bold);
boolean italic = italicCheck.isSelected();
StyleConstants.setItalic(style, italic);
}
// Load the form from an existing Style.
public void loadFromStyle(Style style) {
nameField.setText(style.getName());
nameField.setEditable(false); // don"t allow name change
String fam = StyleConstants.getFontFamily(style);
fontCombo.setSelectedItem(fam);
int size = StyleConstants.getFontSize(style);
sizeCombo.setSelectedItem(Integer.toString(size));
float left = StyleConstants.getLeftIndent(style);
leftField.setText(Float.toString(left));
float right = StyleConstants.getRightIndent(style);
rightField.setText(Float.toString(right));
float above = StyleConstants.getSpaceAbove(style);
aboveField.setText(Float.toString(above));
float below = StyleConstants.getSpaceBelow(style);
belowField.setText(Float.toString(below));
boolean bold = StyleConstants.isBold(style);
boldCheck.setSelected(bold);
boolean italic = StyleConstants.isItalic(style);
italicCheck.setSelected(italic);
}
}
An example that shows lots of little UndoManager details
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// UndoManagerDetails.java
//An example that shows lots of little UndoManager details
//
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
public class UndoManagerDetails {
public static void main(String[] args) {
UndoManager mgr = new UndoManager();
// Show how insignificant edits are skipped over.
//
// # adds? sig? replace?
mgr.addEdit(new SampleUndoableEdit(1, false, true, false));
mgr.addEdit(new SampleUndoableEdit(2, false, true, false));
mgr.addEdit(new SampleUndoableEdit(3, false, false, false));
mgr.addEdit(new SampleUndoableEdit(4, false, false, false));
System.out.println("--------------------------");
System.out.println("Insignificant edit example");
System.out.println("--------------------------");
mgr.undo();
mgr.redo();
System.out.println(mgr.canRedo()); // No more sig. edits
// Show how edits that call add/replace are used.
//
// # adds? sig? replace?
mgr.addEdit(new SampleUndoableEdit(5, true, true, false));
mgr.addEdit(new SampleUndoableEdit(6, false, true, false));
System.out.println("----------------------------------");
System.out.println("Absorbed (by addEdit) edit example");
System.out.println("----------------------------------");
mgr.undo();
mgr.discardAllEdits();
// # adds? sig? replace?
mgr.addEdit(new SampleUndoableEdit(1, false, true, false));
mgr.addEdit(new SampleUndoableEdit(2, false, true, true));
System.out.println("--------------------------------------");
System.out.println("Absorbed (by replaceEdit) edit example");
System.out.println("--------------------------------------");
mgr.undo();
System.out.println(mgr.canUndo());
// Show how changing limit works.
mgr.discardAllEdits();
// # adds? sig? replace?
mgr.addEdit(new SampleUndoableEdit(1, false, true, false));
mgr.addEdit(new SampleUndoableEdit(2, false, true, false));
mgr.addEdit(new SampleUndoableEdit(3, false, true, false));
mgr.addEdit(new SampleUndoableEdit(4, false, true, false));
mgr.addEdit(new SampleUndoableEdit(5, false, true, false));
mgr.addEdit(new SampleUndoableEdit(6, false, true, false));
System.out.println("----------------------");
System.out.println("Changing limit example");
System.out.println("----------------------");
mgr.undo();
mgr.undo();
mgr.undo(); // Now 3 undoable, 3 redoable
mgr.setLimit(4); // Now 2 undoable, 2 redoable!
while (mgr.canUndo())
mgr.undo();
while (mgr.canRedo())
mgr.redo();
// undoOrRedo example
mgr.discardAllEdits();
mgr.setLimit(1);
// # adds? sig? replace?
mgr.addEdit(new SampleUndoableEdit(1, false, true, false));
System.out.println("------------------");
System.out.println("undoOrRedo example");
System.out.println("------------------");
System.out.println(mgr.getUndoOrRedoPresentationName());
mgr.undoOrRedo();
System.out.println(mgr.getUndoOrRedoPresentationName());
mgr.undoOrRedo();
// Show how UndoManager becomes a CompositeEdit.
mgr.discardAllEdits();
mgr.setLimit(100);
// # adds? sig? replace?
mgr.addEdit(new SampleUndoableEdit(1, false, true, false));
mgr.addEdit(new SampleUndoableEdit(2, false, true, false));
mgr.addEdit(new SampleUndoableEdit(3, false, true, false));
System.out.println("------------------------------");
System.out.println("Transform to composite example");
System.out.println("------------------------------");
mgr.end();
mgr.undo();
mgr.redo();
// Show that adds are no longer allowed. Note that addEdit() returns
// true in
// pre-JDK 1.2 Swing releases. This is fixed in JDK 1.2.
System.out.println(mgr.addEdit(new SampleUndoableEdit(4, false, true,
false)));
mgr.undo(); // note that edit 4 is not there
}
}
//SampleUndoableEdit.java
//A simple (?) example of an undoable edit.
//
class SampleUndoableEdit extends AbstractUndoableEdit {
private boolean isSignificant;
private boolean isReplacer;
private int number;
private boolean allowAdds;
private Vector addedEdits;
private UndoableEdit replaced;
// Create a new edit with an identifying number. The boolean arguments
// define
// the edit"s behavior.
public SampleUndoableEdit(int number, boolean allowAdds,
boolean isSignificant, boolean isReplacer) {
this.number = number;
this.allowAdds = allowAdds;
if (allowAdds)
addedEdits = new Vector();
this.isSignificant = isSignificant;
this.isReplacer = isReplacer;
}
// "Undo" the edit by printing a message to the screen.
public void undo() throws CannotUndoException {
super.undo();
System.out.print("Undo " + number);
dumpState();
}
// "Redo" the edit by printing a message to the screen.
public void redo() throws CannotRedoException {
super.redo();
System.out.print("Redo " + number);
dumpState();
}
// If allowAdds is true, we store the input edit. If not, just return false.
public boolean addEdit(UndoableEdit anEdit) {
if (allowAdds) {
addedEdits.addElement(anEdit);
return true;
} else
return false;
}
// If isReplacer is true, we store the edit we are replacing.
public boolean replaceEdit(UndoableEdit anEdit) {
if (isReplacer) {
replaced = anEdit;
return true;
} else
return false;
}
// Significance is based on constructor parameter.
public boolean isSignificant() {
return isSignificant;
}
// Just return our identifier.
public String toString() {
return "<" + number + ">";
}
// Debug output.
public void dumpState() {
if (allowAdds && addedEdits.size() > 0) {
Enumeration e = addedEdits.elements();
System.out.print(" (absorbed: ");
while (e.hasMoreElements()) {
System.out.print(e.nextElement());
}
System.out.print(")");
}
if (isReplacer && replaced != null) {
System.out.print(" (replaced: " + replaced + ")");
}
System.out.println();
}
}
A sample app showing the use of UndoableToggleEdit and CompoundEdit
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// UndoableToggleApp2.java
//A sample app showing the use of UndoableToggleEdit and CompoundEdit.
//
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import javax.swing.JToggleButton;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.rupoundEdit;
import javax.swing.undo.UndoableEdit;
public class UndoableToggleApp2 extends JFrame {
private CompoundEdit edit;
private JButton undoButton;
private JButton redoButton;
private JButton endButton;
// Create the main frame and everything in it.
public UndoableToggleApp2() {
// Create some toggle buttons (and subclasses)
JToggleButton tog = new JToggleButton("ToggleButton");
JCheckBox cb = new JCheckBox("CompoundEdit ExampleCheckBox");
JRadioButton radio = new JRadioButton("RadioButton");
// Add our listener to each toggle button
SimpleListener sl = new SimpleListener();
tog.addActionListener(sl);
cb.addActionListener(sl);
radio.addActionListener(sl);
// Lay out the buttons
Box buttonBox = new Box(BoxLayout.Y_AXIS);
buttonBox.add(tog);
buttonBox.add(cb);
buttonBox.add(radio);
// Create undo and redo buttons (initially disabled)
undoButton = new JButton("Undo");
redoButton = new JButton("Redo");
endButton = new JButton("End");
undoButton.setEnabled(false);
redoButton.setEnabled(false);
endButton.setEnabled(false);
// Add a listener to the undo button. It attempts to call undo() on the
// current edit, then enables/disables the undo/redo buttons as
// appropriate.
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
edit.undo();
} catch (CannotUndoException ex) {
ex.printStackTrace();
} finally {
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
}
});
// Add a redo listener: just like the undo listener, but for redo this
// time.
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
edit.redo();
} catch (CannotRedoException ex) {
ex.printStackTrace();
} finally {
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
}
});
// Add an end listener. This listener will call end() on the
// CompoundEdit
// and update the undo/redo buttons.
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
edit.end();
endButton.setEnabled(false);
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
});
// Layout the undo/redo/end buttons
Box undoRedoEndBox = new Box(BoxLayout.X_AXIS);
undoRedoEndBox.add(Box.createGlue());
undoRedoEndBox.add(undoButton);
undoRedoEndBox.add(Box.createHorizontalStrut(2));
undoRedoEndBox.add(redoButton);
undoRedoEndBox.add(Box.createHorizontalStrut(2));
undoRedoEndBox.add(endButton);
undoRedoEndBox.add(Box.createGlue());
// Layout the main frame
Container content = getContentPane();
content.setLayout(new BorderLayout());
content.add(buttonBox, BorderLayout.CENTER);
content.add(undoRedoEndBox, BorderLayout.SOUTH);
setSize(400, 150);
}
public class SimpleListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
if (edit == null || edit.isInProgress() == false)
edit = new CompoundEdit();
JToggleButton tb = (JToggleButton) ev.getSource();
UndoableEdit togEdit = new UndoableToggleEdit(tb);
edit.addEdit(togEdit);
endButton.setEnabled(true);
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
}
// Main program just creates the frame and displays it.
public static void main(String[] args) {
JFrame f = new UndoableToggleApp2();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
//UndoableToggleEdit.java
//An UndoableEdit used to undo the pressing of a JToggleButton.
//
class UndoableToggleEdit extends AbstractUndoableEdit {
private JToggleButton button;
private boolean selected;
// Create a new edit for a JToggleButton that has just been toggled.
public UndoableToggleEdit(JToggleButton button) {
this.button = button;
selected = button.isSelected();
}
// Return a reasonable name for this edit.
public String getPresentationName() {
return "Toggle " + button.getText() + " " + (selected ? "on" : "off");
}
// Redo by setting the button state as it was initially.
public void redo() throws CannotRedoException {
super.redo();
button.setSelected(selected);
}
// Undo by setting the button state to the opposite value.
public void undo() throws CannotUndoException {
super.undo();
button.setSelected(!selected);
}
}
Bind the undo action to ctl-Z
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class Main {
public static void main(String[] argv) {
JTextComponent textcomp = new JTextArea();
final UndoManager undo = new UndoManager();
Document doc = textcomp.getDocument();
doc.addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undo.addEdit(evt.getEdit());
}
});
textcomp.getActionMap().put("Undo", new AbstractAction("Undo") {
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canUndo()) {
undo.undo();
}
} catch (CannotUndoException e) {
}
}
});
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(textcomp));
frame.setSize(380, 320);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Create an undo action and add it to the text component
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class Main {
public static void main(String[] argv) {
JTextComponent textcomp = new JTextArea();
final UndoManager undo = new UndoManager();
Document doc = textcomp.getDocument();
doc.addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undo.addEdit(evt.getEdit());
}
});
textcomp.getActionMap().put("Undo", new AbstractAction("Undo") {
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canUndo()) {
undo.undo();
}
} catch (CannotUndoException e) {
}
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(textcomp));
frame.setSize(380, 320);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Create a redo action and add it to the text component (JTextComponent)
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class Main {
public static void main(String[] argv) {
JTextComponent textcomp = new JTextArea();
final UndoManager undo = new UndoManager();
Document doc = textcomp.getDocument();
doc.addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undo.addEdit(evt.getEdit());
}
});
textcomp.getActionMap().put("Undo", new AbstractAction("Undo") {
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canUndo()) {
undo.undo();
}
} catch (CannotUndoException e) {
}
}
});
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
textcomp.getActionMap().put("Redo", new AbstractAction("Redo") {
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canRedo()) {
undo.redo();
}
} catch (CannotRedoException e) {
}
}
});
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(textcomp));
frame.setSize(380, 320);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Creating TextArea with Undo, Redo Capabilities
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
class UndoableTextArea extends JTextArea implements UndoableEditListener, FocusListener,
KeyListener {
private UndoManager m_undoManager;
public UndoableTextArea() {
this(new String());
}
public UndoableTextArea(String text) {
super(text);
getDocument().addUndoableEditListener(this);
this.addKeyListener(this);
this.addFocusListener(this);
}
private void createUndoMananger() {
m_undoManager = new UndoManager();
m_undoManager.setLimit(10);
}
private void removeUndoMananger() {
m_undoManager.end();
}
public void focusGained(FocusEvent fe) {
createUndoMananger();
}
public void focusLost(FocusEvent fe) {
removeUndoMananger();
}
public void undoableEditHappened(UndoableEditEvent e) {
m_undoManager.addEdit(e.getEdit());
}
public void keyPressed(KeyEvent e) {
if ((e.getKeyCode() == KeyEvent.VK_Z) && (e.isControlDown())) {
try {
m_undoManager.undo();
} catch (CannotUndoException cue) {
Toolkit.getDefaultToolkit().beep();
}
}
if ((e.getKeyCode() == KeyEvent.VK_Y) && (e.isControlDown())) {
try {
m_undoManager.redo();
} catch (CannotRedoException cue) {
Toolkit.getDefaultToolkit().beep();
}
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
public class Main extends JFrame {
UndoableTextArea m_undoableTextArea = new UndoableTextArea();
public Main() {
JScrollPane sc = new JScrollPane(m_undoableTextArea);
getContentPane().setLayout(new BorderLayout(10, 10));
getContentPane()
.add(BorderLayout.NORTH, new JLabel("Press, CTRL+Z to Undo, CTRL+Y to Redo..."));
getContentPane().add(BorderLayout.CENTER, sc);
}
public static void main(String[] arg) {
Main m = new Main();
m.setVisible(true);
m.setSize(new Dimension(400, 300));
m.validate();
}
}
Listen for undo and redo events
public class Main{
public static void main(String[] argv){
JTextComponent textcomp = new JTextArea();
final UndoManager undo = new UndoManager();
Document doc = textcomp.getDocument();
doc.addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undo.addEdit(evt.getEdit());
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(textcomp));
frame.setSize(380, 320);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}}
Simple GUI demo of UndoManager and friends
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
* All rights reserved. Software written by Ian F. Darwin and others.
* $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
* cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
* pioneering role in inventing and promulgating (and standardizing) the Java
* language and environment is gratefully acknowledged.
*
* The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
* inventing predecessor languages C and C++ is also gratefully acknowledged.
*/
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.undo.UndoManager;
/**
* Simple GUI demo of UndoManager and friends.
*
* @author Ian Darwin http://www.darwinsys.ru/
*/
public class UndoDemo extends JFrame {
JTextArea ta;
UndoManager um;
/** Simple main program that just constructs and shows the GUI */
public static void main(String[] files) {
new UndoDemo().setVisible(true);
}
/** Construct a GUI that demonstrates use of UndoManager */
public UndoDemo() {
Container cp = getContentPane();
cp.add(ta = new JTextArea(20, 60), BorderLayout.CENTER);
JPanel bp;
cp.add(bp = new JPanel(), BorderLayout.SOUTH);
// Create a javax.swing.undo.UndoManager; this is an amazing class that
// keeps a Stack of UndoableEdits and lets you invoke them;
// by registering it as a Listener on the TextComponent.Document,
// the Document will create the UndoableEdit objects and send them
// to the UndoManager. Between them they do ALL the work!
um = new UndoManager();
ta.getDocument().addUndoableEditListener(um);
// Create the buttons
JButton cutButton, copyButton, pasteButton, undoButton, redoButton;
bp.add(cutButton = new JButton("Cut"));
cutButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ta.cut();
}
});
bp.add(copyButton = new JButton("Copy"));
copyButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ta.copy();
}
});
bp.add(pasteButton = new JButton("Paste"));
pasteButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ta.paste();
}
});
bp.add(undoButton = new JButton("UnDo"));
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (um.canUndo()) {
um.undo();
} else {
warn("Can"t undo");
}
}
});
bp.add(redoButton = new JButton("ReDo"));
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (um.canRedo()) {
um.redo();
} else {
warn("Can"t redo");
}
}
});
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
void warn(String msg) {
JOptionPane.showMessageDialog(this, "Warning: " + msg, "Warning",
JOptionPane.WARNING_MESSAGE);
}
}
The use of StateEdit(able)
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// UndoableToggleApp4.java
//A sample app showing the use of StateEdit(able).
//
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import javax.swing.JToggleButton;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.StateEdit;
import javax.swing.undo.StateEditable;
public class UndoableToggleApp4 extends JFrame implements StateEditable {
private JToggleButton tog;
private JCheckBox cb;
private JRadioButton radio;
private JButton undoButton;
private JButton redoButton;
private JButton startButton;
private JButton endButton;
private StateEdit edit;
// Create the main frame and everything in it.
public UndoableToggleApp4() {
// Create some toggle buttons (and subclasses).
tog = new JToggleButton("ToggleButton");
cb = new JCheckBox("CheckBox");
radio = new JRadioButton("RadioButton");
// Add our listener to the buttons.
SimpleListener sl = new SimpleListener();
tog.addActionListener(sl);
cb.addActionListener(sl);
radio.addActionListener(sl);
// Lay out the buttons.
Box buttonBox = new Box(BoxLayout.Y_AXIS);
buttonBox.add(tog);
buttonBox.add(cb);
buttonBox.add(radio);
// Create undo, redo, start, and end buttons.
startButton = new JButton("Start");
endButton = new JButton("End");
undoButton = new JButton("Undo");
redoButton = new JButton("Redo");
startButton.setEnabled(true);
endButton.setEnabled(false);
undoButton.setEnabled(false);
redoButton.setEnabled(false);
// Add a listener to the start button. It creates a new StateEdit,
// passing in this frame as the StateEditable.
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
edit = new StateEdit(UndoableToggleApp4.this);
startButton.setEnabled(false);
endButton.setEnabled(true);
//undoButton.setEnabled(edit.canUndo());
//
// NOTE: We really don"t want to be able to undo until end() is
// pressed,
// but StateEdit does not enforce this for us!
undoButton.setEnabled(false);
redoButton.setEnabled(edit.canRedo());
}
});
// Add a listener to the end button. It will call end() on the
// StateEdit.
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
edit.end();
startButton.setEnabled(true);
endButton.setEnabled(false);
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
});
// Add a listener to the undo button. It attempts to call undo() on the
// current edit, then enables/disables the undo/redo buttons as
// appropriate.
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
edit.undo();
} catch (CannotUndoException ex) {
ex.printStackTrace();
} finally {
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
}
});
// Add a redo listener: just like the undo listener.
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
edit.redo();
} catch (CannotRedoException ex) {
ex.printStackTrace();
} finally {
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
}
});
// Lay out the state/end and undo/redo buttons.
Box undoRedoBox = new Box(BoxLayout.X_AXIS);
undoRedoBox.add(Box.createGlue());
undoRedoBox.add(startButton);
undoRedoBox.add(Box.createHorizontalStrut(2));
undoRedoBox.add(endButton);
undoRedoBox.add(Box.createHorizontalStrut(2));
undoRedoBox.add(undoButton);
undoRedoBox.add(Box.createHorizontalStrut(2));
undoRedoBox.add(redoButton);
undoRedoBox.add(Box.createGlue());
// Lay out the main frame.
Container content = getContentPane();
content.setLayout(new BorderLayout());
content.add(buttonBox, BorderLayout.CENTER);
content.add(undoRedoBox, BorderLayout.SOUTH);
setSize(400, 150);
}
public class SimpleListener implements ActionListener {
// When any toggle button is clicked, we turn off the undo and redo
// buttons, reflecting the fact that we can only undo/redo the last
// set of state changes as long as no additional changes have been made.
public void actionPerformed(ActionEvent ev) {
undoButton.setEnabled(false);
redoButton.setEnabled(false);
}
}
// Save the state of the app by storing the current state of the three
// buttons. We"ll use the buttons themselves as keys and their selected
// state as values.
public void storeState(Hashtable ht) {
ht.put(tog, new Boolean(tog.isSelected()));
ht.put(cb, new Boolean(cb.isSelected()));
ht.put(radio, new Boolean(radio.isSelected()));
}
// Restore state based on the values we saved when storeState() was called.
// Note that StateEdit discards any state info that did not change from
// between the start state and the end state, so we can"t assume that the
// state for all 3 buttons is in the Hashtable.
public void restoreState(Hashtable ht) {
Boolean b1 = (Boolean) ht.get(tog);
if (b1 != null)
tog.setSelected(b1.booleanValue());
Boolean b2 = (Boolean) ht.get(cb);
if (b2 != null)
cb.setSelected(b2.booleanValue());
Boolean b3 = (Boolean) ht.get(radio);
if (b3 != null)
radio.setSelected(b3.booleanValue());
}
// Main program just creates the frame and displays it.
public static void main(String[] args) {
JFrame f = new UndoableToggleApp4();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
The use of UndoableToggleEdit
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// UndoableToggleApp.java
//A sample app showing the use of UndoableToggleEdit.
//
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import javax.swing.JToggleButton;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoableEdit;
public class UndoableToggleApp extends JFrame {
private UndoableEdit edit;
private JButton undoButton;
private JButton redoButton;
// Create the main frame and everything in it.
public UndoableToggleApp() {
// Create some toggle buttons (and subclasses)
JToggleButton tog = new JToggleButton("ToggleButton");
JCheckBox cb = new JCheckBox("CheckBox");
JRadioButton radio = new JRadioButton("RadioButton");
// Add our listener to each toggle button
SimpleListener sl = new SimpleListener();
tog.addActionListener(sl);
cb.addActionListener(sl);
radio.addActionListener(sl);
// Layout the buttons
Box buttonBox = new Box(BoxLayout.Y_AXIS);
buttonBox.add(tog);
buttonBox.add(cb);
buttonBox.add(radio);
// Create undo and redo buttons (initially disabled)
undoButton = new JButton("Undo");
redoButton = new JButton("Redo");
undoButton.setEnabled(false);
redoButton.setEnabled(false);
// Add a listener to the undo button. It attempts to call undo() on the
// current edit, then enables/disables the undo/redo buttons as
// appropriate.
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
edit.undo();
} catch (CannotUndoException ex) {
ex.printStackTrace();
} finally {
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
}
});
// Add a redo listener: just like the undo listener, but for redo this
// time.
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
edit.redo();
} catch (CannotRedoException ex) {
ex.printStackTrace();
} finally {
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
}
});
// Layout the undo/redo buttons
Box undoRedoBox = new Box(BoxLayout.X_AXIS);
undoRedoBox.add(Box.createGlue());
undoRedoBox.add(undoButton);
undoRedoBox.add(Box.createHorizontalStrut(2));
undoRedoBox.add(redoButton);
undoRedoBox.add(Box.createGlue());
// Layout the main frame
Container content = getContentPane();
content.setLayout(new BorderLayout());
content.add(buttonBox, BorderLayout.CENTER);
content.add(undoRedoBox, BorderLayout.SOUTH);
setSize(400, 150);
}
public class SimpleListener implements ActionListener {
// When a toggle button is clicked, we create a new UndoableToggleEdit
// (which replaces any previous edit). We then get the edit"s undo/redo
// names and set the undo/redo button labels. Finally, we
// enable/disable these buttons by asking the edit what we are
// allowed to do.
public void actionPerformed(ActionEvent ev) {
JToggleButton tb = (JToggleButton) ev.getSource();
edit = new UndoableToggleEdit(tb);
undoButton.setText(edit.getUndoPresentationName());
redoButton.setText(edit.getRedoPresentationName());
undoButton.getParent().validate();
undoButton.setEnabled(edit.canUndo());
redoButton.setEnabled(edit.canRedo());
}
}
// Main program just creates the frame and displays it.
public static void main(String[] args) {
JFrame f = new UndoableToggleApp();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
//UndoableToggleEdit.java
//An UndoableEdit used to undo the pressing of a JToggleButton.
//
class UndoableToggleEdit extends AbstractUndoableEdit {
private JToggleButton button;
private boolean selected;
// Create a new edit for a JToggleButton that has just been toggled.
public UndoableToggleEdit(JToggleButton button) {
this.button = button;
selected = button.isSelected();
}
// Return a reasonable name for this edit.
public String getPresentationName() {
return "Toggle " + button.getText() + " " + (selected ? "on" : "off");
}
// Redo by setting the button state as it was initially.
public void redo() throws CannotRedoException {
super.redo();
button.setSelected(selected);
}
// Undo by setting the button state to the opposite value.
public void undo() throws CannotUndoException {
super.undo();
button.setSelected(!selected);
}
}
The use of UndoManager
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// UndoableToggleApp3.java
//A sample app showing the use of UndoManager.
//
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class UndoableToggleApp3 extends JFrame {
private UndoManager manager = new UndoManager();
private JButton undoButton;
private JButton redoButton;
// Create the main frame and everything in it.
public UndoableToggleApp3() {
// Create some toggle buttons.
UndoableJToggleButton tog1 = new UndoableJToggleButton("One");
UndoableJToggleButton tog2 = new UndoableJToggleButton("Two");
UndoableJToggleButton tog3 = new UndoableJToggleButton("Three");
// Add our listener to each toggle button.
SimpleUEListener sl = new SimpleUEListener();
tog1.addUndoableEditListener(sl);
tog2.addUndoableEditListener(sl);
tog3.addUndoableEditListener(sl);
// Lay out the buttons.
Box buttonBox = new Box(BoxLayout.Y_AXIS);
buttonBox.add(tog1);
buttonBox.add(tog2);
buttonBox.add(tog3);
// Create undo and redo buttons (initially disabled).
undoButton = new JButton("Undo");
redoButton = new JButton("Redo");
undoButton.setEnabled(false);
redoButton.setEnabled(false);
// Add a listener to the undo button. It attempts to call undo() on the
// UndoManager, then enables/disables the undo/redo buttons as
// appropriate.
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
manager.undo();
} catch (CannotUndoException ex) {
ex.printStackTrace();
} finally {
updateButtons();
}
}
});
// Add a redo listener: just like the undo listener.
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
manager.redo();
} catch (CannotRedoException ex) {
ex.printStackTrace();
} finally {
updateButtons();
}
}
});
// Lay out the undo/redo buttons.
Box undoRedoBox = new Box(BoxLayout.X_AXIS);
undoRedoBox.add(Box.createGlue());
undoRedoBox.add(undoButton);
undoRedoBox.add(Box.createHorizontalStrut(2));
undoRedoBox.add(redoButton);
undoRedoBox.add(Box.createGlue());
// Lay out the main frame.
getContentPane().setLayout(new BorderLayout());
getContentPane().add(buttonBox, BorderLayout.CENTER);
getContentPane().add(undoRedoBox, BorderLayout.SOUTH);
setSize(400, 150);
}
public class SimpleUEListener implements UndoableEditListener {
// When an UndoableEditEvent is generated (each time one of the buttons
// is pressed), we add it to the UndoManager and then get the manager"s
// undo/redo names and set the undo/redo button labels. Finally, we
// enable/disable these buttons by asking the manager what we are
// allowed to do.
public void undoableEditHappened(UndoableEditEvent ev) {
manager.addEdit(ev.getEdit());
updateButtons();
}
}
// Method to set the text and state of the undo/redo buttons.
protected void updateButtons() {
undoButton.setText(manager.getUndoPresentationName());
redoButton.setText(manager.getRedoPresentationName());
undoButton.getParent().validate();
undoButton.setEnabled(manager.canUndo());
redoButton.setEnabled(manager.canRedo());
}
// Main program just creates the frame and displays it.
public static void main(String[] args) {
JFrame f = new UndoableToggleApp3();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
//UndoableJToggleButton.java
//Sample undoable toggle button class. Supports only a single listener to
//simplify the code.
//
class UndoableJToggleButton extends JToggleButton {
private UndoableEditListener listener;
// For this example, we"ll just provide one constructor . . .
public UndoableJToggleButton(String txt) {
super(txt);
}
// Set the UndoableEditListener.
public void addUndoableEditListener(UndoableEditListener l) {
listener = l; // Should ideally throw an exception if listener != null
}
// Remove the UndoableEditListener.
public void removeUndoableEditListener(UndoableEditListener l) {
listener = null;
}
// We override this method to call the super implementation first (to fire
// the
// action event) and then fire a new UndoableEditEvent to our listener.
protected void fireActionPerformed(ActionEvent ev) {
// Fire the ActionEvent as usual.
super.fireActionPerformed(ev);
if (listener != null) {
listener.undoableEditHappened(new UndoableEditEvent(this,
new UndoableToggleEdit(this)));
}
}
}
//UndoableToggleEdit.java
//An UndoableEdit used to undo the pressing of a JToggleButton.
//
class UndoableToggleEdit extends AbstractUndoableEdit {
private JToggleButton button;
private boolean selected;
// Create a new edit for a JToggleButton that has just been toggled.
public UndoableToggleEdit(JToggleButton button) {
this.button = button;
selected = button.isSelected();
}
// Return a reasonable name for this edit.
public String getPresentationName() {
return "Toggle " + button.getText() + " " + (selected ? "on" : "off");
}
// Redo by setting the button state as it was initially.
public void redo() throws CannotRedoException {
super.redo();
button.setSelected(selected);
}
// Undo by setting the button state to the opposite value.
public void undo() throws CannotUndoException {
super.undo();
button.setSelected(!selected);
}
}
Undoable Drawing Panel 2
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Hashtable;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.StateEdit;
import javax.swing.undo.StateEditable;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEditSupport;
public class UndoableDrawingPanel2 extends JPanel implements StateEditable {
private static String POLYGON_KEY = "Polygon";
UndoableEditSupport undoableEditSupport = new UndoableEditSupport(this);
Polygon polygon = new Polygon();
public UndoableDrawingPanel2() {
MouseListener mouseListener = new MouseAdapter() {
public void mouseReleased(MouseEvent mouseEvent) {
StateEdit stateEdit = new StateEdit(UndoableDrawingPanel2.this);
polygon.addPoint(mouseEvent.getX(), mouseEvent.getY());
stateEdit.end();
undoableEditSupport.postEdit(stateEdit);
repaint();
}
};
addMouseListener(mouseListener);
}
public void addUndoableEditListener(
UndoableEditListener undoableEditListener) {
undoableEditSupport.addUndoableEditListener(undoableEditListener);
}
public void removeUndoableEditListener(
UndoableEditListener undoableEditListener) {
undoableEditSupport.removeUndoableEditListener(undoableEditListener);
}
public void storeState(Hashtable state) {
state.put(POLYGON_KEY, getPolygon());
}
public void restoreState(Hashtable state) {
Polygon polygon = (Polygon) state.get(POLYGON_KEY);
if (polygon != null) {
setPolygon(polygon);
}
}
public void setPolygon(Polygon newValue) {
polygon = newValue;
repaint();
}
public Polygon getPolygon() {
Polygon returnValue;
if (polygon.npoints == 0) {
returnValue = new Polygon();
} else {
returnValue = new Polygon(polygon.xpoints, polygon.ypoints,
polygon.npoints);
}
return returnValue;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawPolygon(polygon);
}
public static void main(String args[]) {
JFrame frame = new JFrame("Drawing Sample2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
UndoableDrawingPanel2 drawingPanel = new UndoableDrawingPanel2();
UndoManager manager = new UndoManager();
drawingPanel.addUndoableEditListener(manager);
JToolBar toolbar = new JToolBar();
toolbar.add(UndoManagerHelper.getUndoAction(manager));
toolbar.add(UndoManagerHelper.getRedoAction(manager));
Container content = frame.getContentPane();
content.add(toolbar, BorderLayout.NORTH);
content.add(drawingPanel, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
class UndoManagerHelper {
public static Action getUndoAction(UndoManager manager, String label) {
return new UndoAction(manager, label);
}
public static Action getUndoAction(UndoManager manager) {
return new UndoAction(manager, "Undo");
}
public static Action getRedoAction(UndoManager manager, String label) {
return new RedoAction(manager, label);
}
public static Action getRedoAction(UndoManager manager) {
return new RedoAction(manager, "Redo");
}
private abstract static class UndoRedoAction extends AbstractAction {
UndoManager undoManager = new UndoManager();
String errorMessage = "Cannot undo";
String errorTitle = "Undo Problem";
protected UndoRedoAction(UndoManager manager, String name) {
super(name);
undoManager = manager;
}
public void setErrorMessage(String newValue) {
errorMessage = newValue;
}
public void setErrorTitle(String newValue) {
errorTitle = newValue;
}
protected void showMessage(Object source) {
if (source instanceof Component) {
JOptionPane.showMessageDialog((Component) source, errorMessage,
errorTitle, JOptionPane.WARNING_MESSAGE);
} else {
System.err.println(errorMessage);
}
}
}
public static class UndoAction extends UndoRedoAction {
public UndoAction(UndoManager manager, String name) {
super(manager, name);
setErrorMessage("Cannot undo");
setErrorTitle("Undo Problem");
}
public void actionPerformed(ActionEvent actionEvent) {
try {
undoManager.undo();
} catch (CannotUndoException cannotUndoException) {
showMessage(actionEvent.getSource());
}
}
}
public static class RedoAction extends UndoRedoAction {
String errorMessage = "Cannot redo";
String errorTitle = "Redo Problem";
public RedoAction(UndoManager manager, String name) {
super(manager, name);
setErrorMessage("Cannot redo");
setErrorTitle("Redo Problem");
}
public void actionPerformed(ActionEvent actionEvent) {
try {
undoManager.redo();
} catch (CannotRedoException cannotRedoException) {
showMessage(actionEvent.getSource());
}
}
}
}
Undo Drawing
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEditSupport;
public class UndoDrawing {
public static void main(String args[]) {
JFrame frame = new JFrame("Drawing Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
UndoableDrawingPanel drawingPanel = new UndoableDrawingPanel();
UndoManager manager = new UndoManager();
drawingPanel.addUndoableEditListener(manager);
JToolBar toolbar = new JToolBar();
toolbar.add(UndoManagerHelper.getUndoAction(manager));
toolbar.add(UndoManagerHelper.getRedoAction(manager));
Container content = frame.getContentPane();
content.add(toolbar, BorderLayout.NORTH);
content.add(drawingPanel, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
class UndoableDrawingPanel extends JPanel {
UndoableEditSupport undoableEditSupport = new UndoableEditSupport(this);
Polygon polygon = new Polygon();
public UndoableDrawingPanel() {
MouseListener mouseListener = new MouseAdapter() {
public void mouseReleased(MouseEvent mouseEvent) {
undoableEditSupport.postEdit(new UndoableDrawEdit(
UndoableDrawingPanel.this));
polygon.addPoint(mouseEvent.getX(), mouseEvent.getY());
repaint();
}
};
addMouseListener(mouseListener);
}
public void addUndoableEditListener(
UndoableEditListener undoableEditListener) {
undoableEditSupport.addUndoableEditListener(undoableEditListener);
}
public void removeUndoableEditListener(
UndoableEditListener undoableEditListener) {
undoableEditSupport.removeUndoableEditListener(undoableEditListener);
}
public void setPolygon(Polygon newValue) {
polygon = newValue;
repaint();
}
public Polygon getPolygon() {
Polygon returnValue;
if (polygon.npoints == 0) {
returnValue = new Polygon();
} else {
returnValue = new Polygon(polygon.xpoints, polygon.ypoints,
polygon.npoints);
}
return returnValue;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawPolygon(polygon);
}
}
class UndoManagerHelper {
public static Action getUndoAction(UndoManager manager, String label) {
return new UndoAction(manager, label);
}
public static Action getUndoAction(UndoManager manager) {
return new UndoAction(manager, "Undo");
}
public static Action getRedoAction(UndoManager manager, String label) {
return new RedoAction(manager, label);
}
public static Action getRedoAction(UndoManager manager) {
return new RedoAction(manager, "Redo");
}
private abstract static class UndoRedoAction extends AbstractAction {
UndoManager undoManager = new UndoManager();
String errorMessage = "Cannot undo";
String errorTitle = "Undo Problem";
protected UndoRedoAction(UndoManager manager, String name) {
super(name);
undoManager = manager;
}
public void setErrorMessage(String newValue) {
errorMessage = newValue;
}
public void setErrorTitle(String newValue) {
errorTitle = newValue;
}
protected void showMessage(Object source) {
if (source instanceof Component) {
JOptionPane.showMessageDialog((Component) source, errorMessage,
errorTitle, JOptionPane.WARNING_MESSAGE);
} else {
System.err.println(errorMessage);
}
}
}
public static class UndoAction extends UndoRedoAction {
public UndoAction(UndoManager manager, String name) {
super(manager, name);
setErrorMessage("Cannot undo");
setErrorTitle("Undo Problem");
}
public void actionPerformed(ActionEvent actionEvent) {
try {
undoManager.undo();
} catch (CannotUndoException cannotUndoException) {
showMessage(actionEvent.getSource());
}
}
}
public static class RedoAction extends UndoRedoAction {
String errorMessage = "Cannot redo";
String errorTitle = "Redo Problem";
public RedoAction(UndoManager manager, String name) {
super(manager, name);
setErrorMessage("Cannot redo");
setErrorTitle("Redo Problem");
}
public void actionPerformed(ActionEvent actionEvent) {
try {
undoManager.redo();
} catch (CannotRedoException cannotRedoException) {
showMessage(actionEvent.getSource());
}
}
}
}
class UndoableDrawEdit extends AbstractUndoableEdit {
UndoableDrawingPanel panel;
Polygon polygon, savedPolygon;
public UndoableDrawEdit(UndoableDrawingPanel panel) {
this.panel = panel;
polygon = panel.getPolygon();
}
public String getPresentationName() {
return "Polygon of size " + polygon.npoints;
}
public void redo() throws CannotRedoException {
super.redo();
if (savedPolygon == null) {
// Should never get here, as super() doesn"t permit redoing
throw new CannotRedoException();
} else {
panel.setPolygon(savedPolygon);
savedPolygon = null;
}
}
public void undo() throws CannotUndoException {
super.undo();
savedPolygon = panel.getPolygon();
panel.setPolygon(polygon);
}
}
Undo Example 1
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;
public class UndoExample1 extends JFrame {
public UndoExample1() {
super("Undo/Redo Example 1");
pane = new JTextPane();
pane.setEditable(true); // Editable
getContentPane().add(new JScrollPane(pane), "Center");
// Add a menu bar
menuBar = new JMenuBar();
setJMenuBar(menuBar);
// Populate the menu bar
createMenuBar();
}
public void createMenuBar() {
// Remove the existing menu items
int count = menuBar.getMenuCount();
for (int i = 0; i < count; i++) {
menuBar.remove(menuBar.getMenu(0));
}
// Build the new menu.
Action[] actions = pane.getActions();
Hashtable actionHash = new Hashtable();
count = actions.length;
for (int i = 0; i < count; i++) {
actionHash.put(actions[i].getValue(Action.NAME), actions[i]);
}
// Add the font menu
JMenu menu = MenuBuilder.buildMenu("Font", fontSpec, actionHash);
if (menu != null) {
menuBar.add(menu);
}
// Add the alignment menu
menu = MenuBuilder.buildMenu("Align", alignSpec, actionHash);
if (menu != null) {
menuBar.add(menu);
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new UndoExample1();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.setSize(250, 300);
f.setVisible(true);
// Create and show a frame monitoring undoable edits
JFrame undoMonitor = new JFrame("Undo Monitor");
final JTextArea textArea = new JTextArea();
textArea.setEditable(false);
undoMonitor.getContentPane().add(new JScrollPane(textArea));
undoMonitor.setBounds(f.getLocation().x + f.getSize().width,
f.getLocation().y, 400, 200);
undoMonitor.setVisible(true);
pane.getDocument().addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
UndoableEdit edit = evt.getEdit();
textArea.append(edit.getPresentationName() + "(" +
edit.toString() + ")\n");
}
});
// Create and show a frame monitoring document edits
JFrame editMonitor = new JFrame("Edit Monitor");
final JTextArea textArea2 = new JTextArea();
textArea2.setEditable(false);
editMonitor.getContentPane().add(new JScrollPane(textArea2));
editMonitor.setBounds(undoMonitor.getLocation().x,
undoMonitor.getLocation().y + undoMonitor.getSize().height,
400, 200);
editMonitor.setVisible(true);
pane.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent evt) {
textArea2.append("Attribute change\n");
}
public void insertUpdate(DocumentEvent evt) {
textArea2.append("Text insertion\n");
}
public void removeUpdate(DocumentEvent evt) {
textArea2.append("Text removal\n");
}
});
}
private static JTextPane pane;
private static JMenuBar menuBar;
private static MenuSpec[] sizeSpec = new MenuSpec[] {
new MenuSpec("Size 8", "font-size-8"),
new MenuSpec("Size 10", "font-size-10"),
new MenuSpec("Size 12", "font-size-12"),
new MenuSpec("Size 14", "font-size-14"),
new MenuSpec("Size 16", "font-size-16"),
new MenuSpec("Size 18", "font-size-18"),
new MenuSpec("Size 24", "font-size-24"),
new MenuSpec("Size 36", "font-size-36"),
new MenuSpec("Size 48", "font-size-48")
};
private static MenuSpec[] familySpec = new MenuSpec[] {
new MenuSpec("Sans Serif", "font-family-SansSerif"),
new MenuSpec("Monospaced", "font-family-Monospaced"),
new MenuSpec("Serif", "font-family-Serif")
};
private static MenuSpec[] styleSpec = new MenuSpec[] {
new MenuSpec("Bold", "font-bold"),
new MenuSpec("Italics", "font-italic"),
new MenuSpec("Underline", "font-underline")
};
// Menu definitions for fonts
private static MenuSpec[] fontSpec = new MenuSpec[] {
new MenuSpec("Size", sizeSpec),
new MenuSpec("Family", familySpec),
new MenuSpec("Style", styleSpec)
};
// Alignment
private static MenuSpec[] alignSpec = new MenuSpec[] {
new MenuSpec("Left", "left-justify"),
new MenuSpec("Center", "center-justify"),
new MenuSpec("Right", "right-justify")
};
}
class MenuSpec {
public MenuSpec(String name, MenuSpec[] subMenus) {
this.name = name;
this.subMenus = subMenus;
}
public MenuSpec(String name, String actionName) {
this.name = name;
this.actionName = actionName;
}
public MenuSpec(String name, Action action) {
this.name = name;
this.action = action;
}
public boolean isSubMenu() {
return subMenus != null;
}
public boolean isAction() {
return action != null;
}
public String getName() {
return name;
}
public MenuSpec[] getSubMenus() {
return subMenus;
}
public String getActionName() {
return actionName;
}
public Action getAction() {
return action;
}
private String name;
private String actionName;
private Action action;
private MenuSpec[] subMenus;
}
class MenuBuilder {
public static JMenu buildMenu(String name, MenuSpec[] menuSpecs,
Hashtable actions) {
int count = menuSpecs.length;
JMenu menu = new JMenu(name);
for (int i = 0; i < count; i++) {
MenuSpec spec = menuSpecs[i];
if (spec.isSubMenu()) {
// Recurse to handle a sub menu
JMenu subMenu = buildMenu(spec.getName(), spec.getSubMenus(),
actions);
if (subMenu != null) {
menu.add(subMenu);
}
} else if (spec.isAction()) {
// It"s an Action - add it directly to the menu
menu.add(spec.getAction());
} else {
// It"s an action name - add it if possible
String actionName = spec.getActionName();
Action targetAction = (Action) actions.get(actionName);
// Create the menu item
JMenuItem menuItem = menu.add(spec.getName());
if (targetAction != null) {
// The editor kit knows the action
menuItem.addActionListener(targetAction);
} else {
// Action not known - disable the menu item
menuItem.setEnabled(false);
}
}
}
// Return null if nothing was added to the menu.
if (menu.getMenuComponentCount() == 0) {
menu = null;
}
return menu;
}
}
Undo Example 2
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Hashtable;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
public class UndoExample2 extends JFrame {
public UndoExample2() {
super("Undo/Redo Example 2");
pane = new JTextPane();
pane.setEditable(true); // Editable
getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
// Add a menu bar
menuBar = new JMenuBar();
setJMenuBar(menuBar);
// Populate the menu bar
createMenuBar();
// Create the undo manager and actions
UndoManager manager = new UndoManager();
pane.getDocument().addUndoableEditListener(manager);
Action undoAction = new UndoAction(manager);
Action redoAction = new RedoAction(manager);
// Add the actions to buttons
JPanel panel = new JPanel();
JButton undoButton = new JButton("Undo");
JButton redoButton = new JButton("Redo");
undoButton.addActionListener(undoAction);
redoButton.addActionListener(redoAction);
panel.add(undoButton);
panel.add(redoButton);
getContentPane().add(panel, BorderLayout.SOUTH);
// Assign the actions to keys
pane.registerKeyboardAction(undoAction, KeyStroke.getKeyStroke(
KeyEvent.VK_Z, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED);
pane.registerKeyboardAction(redoAction, KeyStroke.getKeyStroke(
KeyEvent.VK_Y, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED);
}
public void createMenuBar() {
// Remove the existing menu items
int count = menuBar.getMenuCount();
for (int i = 0; i < count; i++) {
menuBar.remove(menuBar.getMenu(0));
}
// Build the new menu.
Action[] actions = pane.getActions();
Hashtable actionHash = new Hashtable();
count = actions.length;
for (int i = 0; i < count; i++) {
actionHash.put(actions[i].getValue(Action.NAME), actions[i]);
}
// Add the font menu
JMenu menu = MenuBuilder.buildMenu("Font", fontSpec, actionHash);
if (menu != null) {
menuBar.add(menu);
}
// Add the alignment menu
menu = MenuBuilder.buildMenu("Align", alignSpec, actionHash);
if (menu != null) {
menuBar.add(menu);
}
}
// The Undo action
public class UndoAction extends AbstractAction {
public UndoAction(UndoManager manager) {
this.manager = manager;
}
public void actionPerformed(ActionEvent evt) {
try {
manager.undo();
} catch (CannotUndoException e) {
Toolkit.getDefaultToolkit().beep();
}
}
private UndoManager manager;
}
// The Redo action
public class RedoAction extends AbstractAction {
public RedoAction(UndoManager manager) {
this.manager = manager;
}
public void actionPerformed(ActionEvent evt) {
try {
manager.redo();
} catch (CannotRedoException e) {
Toolkit.getDefaultToolkit().beep();
}
}
private UndoManager manager;
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new UndoExample2();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.setSize(250, 300);
f.setVisible(true);
// Create and show a frame monitoring undoable edits
JFrame undoMonitor = new JFrame("Undo Monitor");
final JTextArea textArea = new JTextArea();
textArea.setEditable(false);
undoMonitor.getContentPane().add(new JScrollPane(textArea));
undoMonitor.setBounds(f.getLocation().x + f.getSize().width, f
.getLocation().y, 400, 200);
undoMonitor.setVisible(true);
pane.getDocument().addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
UndoableEdit edit = evt.getEdit();
textArea.append(edit.getPresentationName() + "("
+ edit.toString() + ")\n");
}
});
// Create and show a frame monitoring document edits
JFrame editMonitor = new JFrame("Edit Monitor");
final JTextArea textArea2 = new JTextArea();
textArea2.setEditable(false);
editMonitor.getContentPane().add(new JScrollPane(textArea2));
editMonitor.setBounds(undoMonitor.getLocation().x, undoMonitor
.getLocation().y
+ undoMonitor.getSize().height, 400, 200);
editMonitor.setVisible(true);
pane.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent evt) {
textArea2.append("Attribute change\n");
}
public void insertUpdate(DocumentEvent evt) {
textArea2.append("Text insertion\n");
}
public void removeUpdate(DocumentEvent evt) {
textArea2.append("Text removal\n");
}
});
}
private static JTextPane pane;
private static JMenuBar menuBar;
private static MenuSpec[] sizeSpec = new MenuSpec[] {
new MenuSpec("Size 8", "font-size-8"),
new MenuSpec("Size 10", "font-size-10"),
new MenuSpec("Size 12", "font-size-12"),
new MenuSpec("Size 14", "font-size-14"),
new MenuSpec("Size 16", "font-size-16"),
new MenuSpec("Size 18", "font-size-18"),
new MenuSpec("Size 24", "font-size-24"),
new MenuSpec("Size 36", "font-size-36"),
new MenuSpec("Size 48", "font-size-48") };
private static MenuSpec[] familySpec = new MenuSpec[] {
new MenuSpec("Sans Serif", "font-family-SansSerif"),
new MenuSpec("Monospaced", "font-family-Monospaced"),
new MenuSpec("Serif", "font-family-Serif") };
private static MenuSpec[] styleSpec = new MenuSpec[] {
new MenuSpec("Bold", "font-bold"),
new MenuSpec("Italics", "font-italic"),
new MenuSpec("Underline", "font-underline") };
// Menu definitions for fonts
private static MenuSpec[] fontSpec = new MenuSpec[] {
new MenuSpec("Size", sizeSpec), new MenuSpec("Family", familySpec),
new MenuSpec("Style", styleSpec) };
// Alignment
private static MenuSpec[] alignSpec = new MenuSpec[] {
new MenuSpec("Left", "left-justify"),
new MenuSpec("Center", "center-justify"),
new MenuSpec("Right", "right-justify") };
}
class MenuSpec {
public MenuSpec(String name, MenuSpec[] subMenus) {
this.name = name;
this.subMenus = subMenus;
}
public MenuSpec(String name, String actionName) {
this.name = name;
this.actionName = actionName;
}
public MenuSpec(String name, Action action) {
this.name = name;
this.action = action;
}
public boolean isSubMenu() {
return subMenus != null;
}
public boolean isAction() {
return action != null;
}
public String getName() {
return name;
}
public MenuSpec[] getSubMenus() {
return subMenus;
}
public String getActionName() {
return actionName;
}
public Action getAction() {
return action;
}
private String name;
private String actionName;
private Action action;
private MenuSpec[] subMenus;
}
class MenuBuilder {
public static JMenu buildMenu(String name, MenuSpec[] menuSpecs,
Hashtable actions) {
int count = menuSpecs.length;
JMenu menu = new JMenu(name);
for (int i = 0; i < count; i++) {
MenuSpec spec = menuSpecs[i];
if (spec.isSubMenu()) {
// Recurse to handle a sub menu
JMenu subMenu = buildMenu(spec.getName(), spec.getSubMenus(),
actions);
if (subMenu != null) {
menu.add(subMenu);
}
} else if (spec.isAction()) {
// It"s an Action - add it directly to the menu
menu.add(spec.getAction());
} else {
// It"s an action name - add it if possible
String actionName = spec.getActionName();
Action targetAction = (Action) actions.get(actionName);
// Create the menu item
JMenuItem menuItem = menu.add(spec.getName());
if (targetAction != null) {
// The editor kit knows the action
menuItem.addActionListener(targetAction);
} else {
// Action not known - disable the menu item
menuItem.setEnabled(false);
}
}
}
// Return null if nothing was added to the menu.
if (menu.getMenuComponentCount() == 0) {
menu = null;
}
return menu;
}
}
Undo Example 3
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.UndoableEditListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEditSupport;
public class UndoExample3 extends JFrame {
public UndoExample3() {
super("Undo/Redo Example 3");
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode node = new DefaultMutableTreeNode("Apollo 8");
rootNode.add(node);
node.add(new DefaultMutableTreeNode("Borman"));
node.add(new DefaultMutableTreeNode("Lovell"));
node.add(new DefaultMutableTreeNode("Anders"));
node = new DefaultMutableTreeNode("Apollo 11");
rootNode.add(node);
node.add(new DefaultMutableTreeNode("Armstrong"));
node.add(new DefaultMutableTreeNode("Aldrin"));
node.add(new DefaultMutableTreeNode("Collins"));
node = new DefaultMutableTreeNode("Apollo 12");
rootNode.add(node);
node.add(new DefaultMutableTreeNode("Conrad"));
node.add(new DefaultMutableTreeNode("Gordon"));
node.add(new DefaultMutableTreeNode("Bean"));
UndoableTree tree = new UndoableTree(rootNode);
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
// Create the undo manager and actions
UndoManager manager = new UndoManager();
tree.addUndoableEditListener(manager);
Action undoAction = new UndoAction(manager);
Action redoAction = new RedoAction(manager);
// Add the actions to buttons
JPanel panel = new JPanel();
JButton undoButton = new JButton("Undo");
JButton redoButton = new JButton("Redo");
undoButton.addActionListener(undoAction);
redoButton.addActionListener(redoAction);
panel.add(undoButton);
panel.add(redoButton);
getContentPane().add(panel, BorderLayout.SOUTH);
// Assign the actions to keys
((JComponent) getContentPane()).registerKeyboardAction(undoAction,
KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK),
JComponent.WHEN_IN_FOCUSED_WINDOW);
((JComponent) getContentPane()).registerKeyboardAction(redoAction,
KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_MASK),
JComponent.WHEN_IN_FOCUSED_WINDOW);
}
// The Undo action
public class UndoAction extends AbstractAction {
public UndoAction(UndoManager manager) {
this.manager = manager;
}
public void actionPerformed(ActionEvent evt) {
try {
manager.undo();
} catch (CannotUndoException e) {
Toolkit.getDefaultToolkit().beep();
}
}
private UndoManager manager;
}
// The Redo action
public class RedoAction extends AbstractAction {
public RedoAction(UndoManager manager) {
this.manager = manager;
}
public void actionPerformed(ActionEvent evt) {
try {
manager.redo();
} catch (CannotRedoException e) {
Toolkit.getDefaultToolkit().beep();
}
}
private UndoManager manager;
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new UndoExample3();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.pack();
f.setVisible(true);
}
}
class UndoableTree extends JTree {
// Only one constructor for brevity
public UndoableTree(TreeNode root) {
super(root);
}
public void addUndoableEditListener(UndoableEditListener l) {
support.addUndoableEditListener(l);
}
public void removeUndoableEditListener(UndoableEditListener l) {
support.removeUndoableEditListener(l);
}
public void collapsePath(TreePath path) {
boolean wasExpanded = isExpanded(path);
super.collapsePath(path);
boolean isExpanded = isExpanded(path);
if (isExpanded != wasExpanded) {
support.postEdit(new CollapseEdit(path));
}
}
public void expandPath(TreePath path) {
boolean wasExpanded = isExpanded(path);
super.expandPath(path);
boolean isExpanded = isExpanded(path);
if (isExpanded != wasExpanded) {
support.postEdit(new ExpandEdit(path));
}
}
private void undoExpansion(TreePath path) {
super.collapsePath(path);
}
private void undoCollapse(TreePath path) {
super.expandPath(path);
}
private class CollapseEdit extends AbstractUndoableEdit {
public CollapseEdit(TreePath path) {
this.path = path;
}
public void undo() throws CannotUndoException {
super.undo();
UndoableTree.this.undoCollapse(path);
}
public void redo() throws CannotRedoException {
super.redo();
UndoableTree.this.undoExpansion(path);
}
public String getPresentationName() {
return "node collapse";
}
private TreePath path;
}
private class ExpandEdit extends AbstractUndoableEdit {
public ExpandEdit(TreePath path) {
this.path = path;
}
public void undo() throws CannotUndoException {
super.undo();
UndoableTree.this.undoExpansion(path);
}
public void redo() throws CannotRedoException {
super.redo();
UndoableTree.this.undoCollapse(path);
}
public String getPresentationName() {
return "node expansion";
}
private TreePath path;
}
private UndoableEditSupport support = new UndoableEditSupport(this);
}
Undo Example 4
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.UndoableEditListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEditSupport;
public class UndoExample4 extends JFrame {
public UndoExample4() {
super("Undo/Redo Example 4");
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode node = new DefaultMutableTreeNode("Apollo 8");
rootNode.add(node);
node.add(new DefaultMutableTreeNode("Borman"));
node.add(new DefaultMutableTreeNode("Lovell"));
node.add(new DefaultMutableTreeNode("Anders"));
node = new DefaultMutableTreeNode("Apollo 11");
rootNode.add(node);
node.add(new DefaultMutableTreeNode("Armstrong"));
node.add(new DefaultMutableTreeNode("Aldrin"));
node.add(new DefaultMutableTreeNode("Collins"));
node = new DefaultMutableTreeNode("Apollo 12");
rootNode.add(node);
node.add(new DefaultMutableTreeNode("Conrad"));
node.add(new DefaultMutableTreeNode("Gordon"));
node.add(new DefaultMutableTreeNode("Bean"));
UndoableTree2 tree = new UndoableTree2(rootNode);
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
// Create the undo manager and actions
UndoManager manager = new UndoManager();
tree.addUndoableEditListener(manager);
Action undoAction = new UndoAction(manager);
Action redoAction = new RedoAction(manager);
// Add the actions to buttons
JPanel panel = new JPanel();
JButton undoButton = new JButton("Undo");
JButton redoButton = new JButton("Redo");
undoButton.addActionListener(undoAction);
redoButton.addActionListener(redoAction);
panel.add(undoButton);
panel.add(redoButton);
getContentPane().add(panel, BorderLayout.SOUTH);
// Assign the actions to keys
((JComponent) getContentPane()).registerKeyboardAction(undoAction,
KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK),
JComponent.WHEN_IN_FOCUSED_WINDOW);
((JComponent) getContentPane()).registerKeyboardAction(redoAction,
KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_MASK),
JComponent.WHEN_IN_FOCUSED_WINDOW);
}
// The Undo action
public class UndoAction extends AbstractAction {
public UndoAction(UndoManager manager) {
this.manager = manager;
}
public void actionPerformed(ActionEvent evt) {
try {
manager.undo();
} catch (CannotUndoException e) {
Toolkit.getDefaultToolkit().beep();
}
}
private UndoManager manager;
}
// The Redo action
public class RedoAction extends AbstractAction {
public RedoAction(UndoManager manager) {
this.manager = manager;
}
public void actionPerformed(ActionEvent evt) {
try {
manager.redo();
} catch (CannotRedoException e) {
Toolkit.getDefaultToolkit().beep();
}
}
private UndoManager manager;
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new UndoExample4();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.pack();
f.setVisible(true);
}
}
class UndoableTree2 extends JTree {
public UndoableTree2(TreeNode root) {
super(root);
}
public void addUndoableEditListener(UndoableEditListener l) {
support.addUndoableEditListener(l);
}
public void removeUndoableEditListener(UndoableEditListener l) {
support.removeUndoableEditListener(l);
}
public void collapsePath(TreePath path) {
boolean wasExpanded = isExpanded(path);
TreePath[] selections = getSelectionPaths();
super.collapsePath(path);
boolean isExpanded = isExpanded(path);
if (isExpanded != wasExpanded) {
TreePath[] newSelections = getSelectionPaths();
support.beginUpdate();
support.postEdit(new SelectionEdit(selections, newSelections));
support.postEdit(new CollapseEdit(path));
support.endUpdate();
}
}
public void expandPath(TreePath path) {
boolean wasExpanded = isExpanded(path);
TreePath[] selections = getSelectionPaths();
super.expandPath(path);
boolean isExpanded = isExpanded(path);
if (isExpanded != wasExpanded) {
TreePath[] newSelections = getSelectionPaths();
support.beginUpdate();
support.postEdit(new SelectionEdit(selections, newSelections));
support.postEdit(new ExpandEdit(path));
support.endUpdate();
}
}
private void undoExpansion(TreePath path) {
super.collapsePath(path);
}
private void undoCollapse(TreePath path) {
super.expandPath(path);
}
private class CollapseEdit extends AbstractUndoableEdit {
public CollapseEdit(TreePath path) {
this.path = path;
}
public void undo() throws CannotUndoException {
super.undo();
UndoableTree2.this.undoCollapse(path);
}
public void redo() throws CannotRedoException {
super.redo();
UndoableTree2.this.undoExpansion(path);
}
public String getPresentationName() {
return "node collapse";
}
private TreePath path;
}
private class ExpandEdit extends AbstractUndoableEdit {
public ExpandEdit(TreePath path) {
this.path = path;
}
public void undo() throws CannotUndoException {
super.undo();
UndoableTree2.this.undoExpansion(path);
}
public void redo() throws CannotRedoException {
super.redo();
UndoableTree2.this.undoCollapse(path);
}
public String getPresentationName() {
return "node expansion";
}
private TreePath path;
}
private class SelectionEdit extends AbstractUndoableEdit {
public SelectionEdit(TreePath[] oldSelections, TreePath[] newSelections) {
this.oldSelections = oldSelections;
this.newSelections = newSelections;
}
public void undo() throws CannotUndoException {
super.undo();
UndoableTree2.this.setSelectionPaths(oldSelections);
}
public void redo() throws CannotRedoException {
super.redo();
UndoableTree2.this.setSelectionPaths(newSelections);
}
public String getPresentationName() {
return "selection change";
}
private TreePath[] oldSelections;
private TreePath[] newSelections;
}
private UndoableEditSupport support = new UndoableEditSupport(this);
}
Undo Example 5
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Hashtable;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.EventListenerList;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
public class UndoExample5 extends JFrame {
public UndoExample5() {
super("Undo/Redo Example 5");
pane = new JTextPane();
pane.setEditable(true); // Editable
getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
// Add a menu bar
menuBar = new JMenuBar();
setJMenuBar(menuBar);
// Populate the menu bar
createMenuBar();
// Create the undo manager and actions
MonitorableUndoManager manager = new MonitorableUndoManager();
pane.getDocument().addUndoableEditListener(manager);
Action undoAction = new UndoAction(manager);
Action redoAction = new RedoAction(manager);
// Add the actions to buttons
JPanel panel = new JPanel();
final JButton undoButton = new JButton("Undo");
final JButton redoButton = new JButton("Redo");
undoButton.addActionListener(undoAction);
redoButton.addActionListener(redoAction);
undoButton.setEnabled(false);
redoButton.setEnabled(false);
panel.add(undoButton);
panel.add(redoButton);
getContentPane().add(panel, BorderLayout.SOUTH);
// Assign the actions to keys
pane.registerKeyboardAction(undoAction, KeyStroke.getKeyStroke(
KeyEvent.VK_Z, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED);
pane.registerKeyboardAction(redoAction, KeyStroke.getKeyStroke(
KeyEvent.VK_Y, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED);
// Handle events from the MonitorableUndoManager
manager.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent evt) {
MonitorableUndoManager m = (MonitorableUndoManager) evt
.getSource();
boolean canUndo = m.canUndo();
boolean canRedo = m.canRedo();
undoButton.setEnabled(canUndo);
redoButton.setEnabled(canRedo);
undoButton.setToolTipText(canUndo ? m.getUndoPresentationName()
: null);
redoButton.setToolTipText(canRedo ? m.getRedoPresentationName()
: null);
}
});
}
public void createMenuBar() {
// Remove the existing menu items
int count = menuBar.getMenuCount();
for (int i = 0; i < count; i++) {
menuBar.remove(menuBar.getMenu(0));
}
// Build the new menu.
Action[] actions = pane.getActions();
Hashtable actionHash = new Hashtable();
count = actions.length;
for (int i = 0; i < count; i++) {
actionHash.put(actions[i].getValue(Action.NAME), actions[i]);
}
// Add the font menu
JMenu menu = MenuBuilder.buildMenu("Font", fontSpec, actionHash);
if (menu != null) {
menuBar.add(menu);
}
// Add the alignment menu
menu = MenuBuilder.buildMenu("Align", alignSpec, actionHash);
if (menu != null) {
menuBar.add(menu);
}
}
// The Undo action
public class UndoAction extends AbstractAction {
public UndoAction(UndoManager manager) {
this.manager = manager;
}
public void actionPerformed(ActionEvent evt) {
try {
manager.undo();
} catch (CannotUndoException e) {
Toolkit.getDefaultToolkit().beep();
}
}
private UndoManager manager;
}
// The Redo action
public class RedoAction extends AbstractAction {
public RedoAction(UndoManager manager) {
this.manager = manager;
}
public void actionPerformed(ActionEvent evt) {
try {
manager.redo();
} catch (CannotRedoException e) {
Toolkit.getDefaultToolkit().beep();
}
}
private UndoManager manager;
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new UndoExample5();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.setSize(250, 300);
f.setVisible(true);
// Create and show a frame monitoring undoable edits
JFrame undoMonitor = new JFrame("Undo Monitor");
final JTextArea textArea = new JTextArea();
textArea.setEditable(false);
undoMonitor.getContentPane().add(new JScrollPane(textArea));
undoMonitor.setBounds(f.getLocation().x + f.getSize().width, f
.getLocation().y, 400, 200);
undoMonitor.setVisible(true);
pane.getDocument().addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
UndoableEdit edit = evt.getEdit();
textArea.append(edit.getPresentationName() + "("
+ edit.toString() + ")\n");
}
});
// Create and show a frame monitoring document edits
JFrame editMonitor = new JFrame("Edit Monitor");
final JTextArea textArea2 = new JTextArea();
textArea2.setEditable(false);
editMonitor.getContentPane().add(new JScrollPane(textArea2));
editMonitor.setBounds(undoMonitor.getLocation().x, undoMonitor
.getLocation().y
+ undoMonitor.getSize().height, 400, 200);
editMonitor.setVisible(true);
pane.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent evt) {
textArea2.append("Attribute change\n");
}
public void insertUpdate(DocumentEvent evt) {
textArea2.append("Text insertion\n");
}
public void removeUpdate(DocumentEvent evt) {
textArea2.append("Text removal\n");
}
});
}
private static JTextPane pane;
private static JMenuBar menuBar;
private static MenuSpec[] sizeSpec = new MenuSpec[] {
new MenuSpec("Size 8", "font-size-8"),
new MenuSpec("Size 10", "font-size-10"),
new MenuSpec("Size 12", "font-size-12"),
new MenuSpec("Size 14", "font-size-14"),
new MenuSpec("Size 16", "font-size-16"),
new MenuSpec("Size 18", "font-size-18"),
new MenuSpec("Size 24", "font-size-24"),
new MenuSpec("Size 36", "font-size-36"),
new MenuSpec("Size 48", "font-size-48") };
private static MenuSpec[] familySpec = new MenuSpec[] {
new MenuSpec("Sans Serif", "font-family-SansSerif"),
new MenuSpec("Monospaced", "font-family-Monospaced"),
new MenuSpec("Serif", "font-family-Serif") };
private static MenuSpec[] styleSpec = new MenuSpec[] {
new MenuSpec("Bold", "font-bold"),
new MenuSpec("Italics", "font-italic"),
new MenuSpec("Underline", "font-underline") };
// Menu definitions for fonts
private static MenuSpec[] fontSpec = new MenuSpec[] {
new MenuSpec("Size", sizeSpec), new MenuSpec("Family", familySpec),
new MenuSpec("Style", styleSpec) };
// Alignment
private static MenuSpec[] alignSpec = new MenuSpec[] {
new MenuSpec("Left", "left-justify"),
new MenuSpec("Center", "center-justify"),
new MenuSpec("Right", "right-justify") };
}
class MonitorableUndoManager extends UndoManager {
// List of listeners for events from this object
protected EventListenerList listenerList = new EventListenerList();
// A ChangeEvent dedicated to a single MonitorableUndoManager
protected ChangeEvent changeEvent;
// Super class overrides
public synchronized void setLimit(int l) {
super.setLimit(l);
fireChangeEvent();
}
public synchronized void discardAllEdits() {
super.discardAllEdits();
fireChangeEvent();
}
public synchronized void undo() throws CannotUndoException {
super.undo();
fireChangeEvent();
}
public synchronized void redo() throws CannotRedoException {
super.redo();
fireChangeEvent();
}
public synchronized boolean addEdit(UndoableEdit anEdit) {
boolean retval = super.addEdit(anEdit);
fireChangeEvent();
return retval;
}
// Support for ChangeListeners
public void addChangeListener(ChangeListener l) {
listenerList.add(ChangeListener.class, l);
}
public void removeChangeListener(ChangeListener l) {
listenerList.remove(ChangeListener.class, l);
}
protected void fireChangeEvent() {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ChangeListener.class) {
if (changeEvent == null) {
changeEvent = new ChangeEvent(this);
}
((ChangeListener) listeners[i + 1]).stateChanged(changeEvent);
}
}
}
}
class MenuSpec {
public MenuSpec(String name, MenuSpec[] subMenus) {
this.name = name;
this.subMenus = subMenus;
}
public MenuSpec(String name, String actionName) {
this.name = name;
this.actionName = actionName;
}
public MenuSpec(String name, Action action) {
this.name = name;
this.action = action;
}
public boolean isSubMenu() {
return subMenus != null;
}
public boolean isAction() {
return action != null;
}
public String getName() {
return name;
}
public MenuSpec[] getSubMenus() {
return subMenus;
}
public String getActionName() {
return actionName;
}
public Action getAction() {
return action;
}
private String name;
private String actionName;
private Action action;
private MenuSpec[] subMenus;
}
class MenuBuilder {
public static JMenu buildMenu(String name, MenuSpec[] menuSpecs,
Hashtable actions) {
int count = menuSpecs.length;
JMenu menu = new JMenu(name);
for (int i = 0; i < count; i++) {
MenuSpec spec = menuSpecs[i];
if (spec.isSubMenu()) {
// Recurse to handle a sub menu
JMenu subMenu = buildMenu(spec.getName(), spec.getSubMenus(),
actions);
if (subMenu != null) {
menu.add(subMenu);
}
} else if (spec.isAction()) {
// It"s an Action - add it directly to the menu
menu.add(spec.getAction());
} else {
// It"s an action name - add it if possible
String actionName = spec.getActionName();
Action targetAction = (Action) actions.get(actionName);
// Create the menu item
JMenuItem menuItem = menu.add(spec.getName());
if (targetAction != null) {
// The editor kit knows the action
menuItem.addActionListener(targetAction);
} else {
// Action not known - disable the menu item
menuItem.setEnabled(false);
}
}
}
// Return null if nothing was added to the menu.
if (menu.getMenuComponentCount() == 0) {
menu = null;
}
return menu;
}
}
Undo Example 6
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.dnd.Autoscroll;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ruparator;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class FileTreeTest {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
try {
JFrame f = new JFrame("File Tree Test");
final FileTree ft = new FileTree("D:\\");
ft.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent evt) {
TreePath path = evt.getPath();
String name = ft.getPathName(path);
System.out.println("File " + name + " has been "
+ (evt.isAddedPath() ? "selected" : "deselected"));
}
});
f.getContentPane().add(new JScrollPane(ft));
f.setSize(300, 300);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.setVisible(true);
} catch (FileNotFoundException e) {
System.out.println("File " + args[0] + " not found");
}
}
}
class FileTree extends JTree implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8);
protected Insets scrollInsets = defaultScrollInsets;
public FileTree(String path) throws FileNotFoundException,
SecurityException {
super((TreeModel) null); // Create the JTree itself
// Use horizontal and vertical lines
putClientProperty("JTree.lineStyle", "Angled");
// Create the first node
FileTreeNode rootNode = new FileTreeNode(null, path);
// Populate the root node with its subdirectories
boolean addedNodes = rootNode.populateDirectories(true);
setModel(new DefaultTreeModel(rootNode));
// Listen for Tree Selection Events
addTreeExpansionListener(new TreeExpansionHandler());
}
// Returns the full pathname for a path, or null if not a known path
public String getPathName(TreePath path) {
Object o = path.getLastPathComponent();
if (o instanceof FileTreeNode) {
return ((FileTreeNode) o).fullName;
}
return null;
}
// Adds a new node to the tree after construction.
// Returns the inserted node, or null if the parent
// directory has not been expanded.
public FileTreeNode addNode(FileTreeNode parent, String name) {
int index = parent.addNode(name);
if (index != -1) {
((DefaultTreeModel) getModel()).nodesWereInserted(parent,
new int[] { index });
return (FileTreeNode) parent.getChildAt(index);
}
// No node was created
return null;
}
// Autoscrolling support
public void setScrollInsets(Insets insets) {
this.scrollInsets = insets;
}
public Insets getScrollInsets() {
return scrollInsets;
}
// Implementation of Autoscroll interface
public Insets getAutoscrollInsets() {
Rectangle r = getVisibleRect();
Dimension size = getSize();
Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left,
size.height - r.y - r.height + scrollInsets.bottom, size.width
- r.x - r.width + scrollInsets.right);
return i;
}
public void autoscroll(Point location) {
JScrollPane scroller = (JScrollPane) SwingUtilities.getAncestorOfClass(
JScrollPane.class, this);
if (scroller != null) {
JScrollBar hBar = scroller.getHorizontalScrollBar();
JScrollBar vBar = scroller.getVerticalScrollBar();
Rectangle r = getVisibleRect();
if (location.x <= r.x + scrollInsets.left) {
// Need to scroll left
hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1));
}
if (location.y <= r.y + scrollInsets.top) {
// Need to scroll up
vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1));
}
if (location.x >= r.x + r.width - scrollInsets.right) {
// Need to scroll right
hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1));
}
if (location.y >= r.y + r.height - scrollInsets.bottom) {
// Need to scroll down
vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1));
}
}
}
// Inner class that represents a node in this file system tree
public static class FileTreeNode extends DefaultMutableTreeNode {
public FileTreeNode(String parent, String name)
throws SecurityException, FileNotFoundException {
this.name = name;
// See if this node exists and whether it is a directory
fullName = parent == null ? name : parent + File.separator + name;
File f = new File(fullName);
if (f.exists() == false) {
throw new FileNotFoundException("File " + fullName
+ " does not exist");
}
isDir = f.isDirectory();
// Hack for Windows which doesn"t consider a drive to be a
// directory!
if (isDir == false && f.isFile() == false) {
isDir = true;
}
}
// Override isLeaf to check whether this is a directory
public boolean isLeaf() {
return !isDir;
}
// Override getAllowsChildren to check whether this is a directory
public boolean getAllowsChildren() {
return isDir;
}
// Return whether this is a directory
public boolean isDir() {
return isDir;
}
// Get full path
public String getFullName() {
return fullName;
}
// For display purposes, we return our own name
public String toString() {
return name;
}
// If we are a directory, scan our contents and populate
// with children. In addition, populate those children
// if the "descend" flag is true. We only descend once,
// to avoid recursing the whole subtree.
// Returns true if some nodes were added
boolean populateDirectories(boolean descend) {
boolean addedNodes = false;
// Do this only once
if (populated == false) {
File f;
try {
f = new File(fullName);
} catch (SecurityException e) {
populated = true;
return false;
}
if (interim == true) {
// We have had a quick look here before:
// remove the dummy node that we added last time
removeAllChildren();
interim = false;
}
String[] names = f.list(); // Get list of contents
// Process the contents
ArrayList list = new ArrayList();
for (int i = 0; i < names.length; i++) {
String name = names[i];
File d = new File(fullName, name);
try {
FileTreeNode node = new FileTreeNode(fullName, name);
list.add(node);
if (descend && d.isDirectory()) {
node.populateDirectories(false);
}
addedNodes = true;
if (descend == false) {
// Only add one node if not descending
break;
}
} catch (Throwable t) {
// Ignore phantoms or access problems
}
}
if (addedNodes == true) {
// Now sort the list of contained files and directories
Object[] nodes = list.toArray();
Arrays.sort(nodes, new Comparator() {
public boolean equals(Object o) {
return false;
}
public int compare(Object o1, Object o2) {
FileTreeNode node1 = (FileTreeNode) o1;
FileTreeNode node2 = (FileTreeNode) o2;
// Directories come first
if (node1.isDir != node2.isDir) {
return node1.isDir ? -1 : +1;
}
// Both directories or both files -
// compare based on pathname
return node1.fullName.rupareTo(node2.fullName);
}
});
// Add sorted items as children of this node
for (int j = 0; j < nodes.length; j++) {
this.add((FileTreeNode) nodes[j]);
}
}
// If we were scanning to get all subdirectories,
// or if we found no content, there is no
// reason to look at this directory again, so
// set populated to true. Otherwise, we set interim
// so that we look again in the future if we need to
if (descend == true || addedNodes == false) {
populated = true;
} else {
// Just set interim state
interim = true;
}
}
return addedNodes;
}
// Adding a new file or directory after
// constructing the FileTree. Returns
// the index of the inserted node.
public int addNode(String name) {
// If not populated yet, do nothing
if (populated == true) {
// Do not add a new node if
// the required node is already there
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
FileTreeNode node = (FileTreeNode) getChildAt(i);
if (node.name.equals(name)) {
// Already exists - ensure
// we repopulate
if (node.isDir()) {
node.interim = true;
node.populated = false;
}
return -1;
}
}
// Add a new node
try {
FileTreeNode node = new FileTreeNode(fullName, name);
add(node);
return childCount;
} catch (Exception e) {
}
}
return -1;
}
protected String name; // Name of this component
protected String fullName; // Full pathname
protected boolean populated;// true if we have been populated
protected boolean interim; // true if we are in interim state
protected boolean isDir; // true if this is a directory
}
// Inner class that handles Tree Expansion Events
protected class TreeExpansionHandler implements TreeExpansionListener {
public void treeExpanded(TreeExpansionEvent evt) {
TreePath path = evt.getPath(); // The expanded path
JTree tree = (JTree) evt.getSource(); // The tree
// Get the last component of the path and
// arrange to have it fully populated.
FileTreeNode node = (FileTreeNode) path.getLastPathComponent();
if (node.populateDirectories(true)) {
((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node);
}
}
public void treeCollapsed(TreeExpansionEvent evt) {
// Nothing to do
}
}
}
Undo Example 7
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.Container;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class UndoSample {
public static void main(String args[]) {
JFrame frame = new JFrame("Undo Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea textArea = new JTextArea();
JScrollPane scrollPane = new JScrollPane(textArea);
UndoManager manager = new UndoManager();
textArea.getDocument().addUndoableEditListener(manager);
JToolBar toolbar = new JToolBar();
toolbar.add(UndoManagerHelper.getUndoAction(manager));
toolbar.add(UndoManagerHelper.getRedoAction(manager));
Container content = frame.getContentPane();
content.add(toolbar, BorderLayout.NORTH);
content.add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
class UndoManagerHelper {
public static Action getUndoAction(UndoManager manager, String label) {
return new UndoAction(manager, label);
}
public static Action getUndoAction(UndoManager manager) {
return new UndoAction(manager, "Undo");
}
public static Action getRedoAction(UndoManager manager, String label) {
return new RedoAction(manager, label);
}
public static Action getRedoAction(UndoManager manager) {
return new RedoAction(manager, "Redo");
}
private abstract static class UndoRedoAction extends AbstractAction {
UndoManager undoManager = new UndoManager();
String errorMessage = "Cannot undo";
String errorTitle = "Undo Problem";
protected UndoRedoAction(UndoManager manager, String name) {
super(name);
undoManager = manager;
}
public void setErrorMessage(String newValue) {
errorMessage = newValue;
}
public void setErrorTitle(String newValue) {
errorTitle = newValue;
}
protected void showMessage(Object source) {
if (source instanceof Component) {
JOptionPane.showMessageDialog((Component) source, errorMessage,
errorTitle, JOptionPane.WARNING_MESSAGE);
} else {
System.err.println(errorMessage);
}
}
}
public static class UndoAction extends UndoRedoAction {
public UndoAction(UndoManager manager, String name) {
super(manager, name);
setErrorMessage("Cannot undo");
setErrorTitle("Undo Problem");
}
public void actionPerformed(ActionEvent actionEvent) {
try {
undoManager.undo();
} catch (CannotUndoException cannotUndoException) {
showMessage(actionEvent.getSource());
}
}
}
public static class RedoAction extends UndoRedoAction {
String errorMessage = "Cannot redo";
String errorTitle = "Redo Problem";
public RedoAction(UndoManager manager, String name) {
super(manager, name);
setErrorMessage("Cannot redo");
setErrorTitle("Redo Problem");
}
public void actionPerformed(ActionEvent actionEvent) {
try {
undoManager.redo();
} catch (CannotRedoException cannotRedoException) {
showMessage(actionEvent.getSource());
}
}
}
}
Undo manager
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.UndoableEditEvent;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.UndoManager;
public class UndoManagerDemo extends JFrame {
protected Vector pointVector = new Vector();
protected PaintCanvas canvas = new PaintCanvas(pointVector);
protected UndoManager undoManager = new UndoManager();
protected JButton undoButton = new JButton("Undo");
protected JButton redoButton = new JButton("Redo");
public UndoManagerDemo() {
super("Undo/Redo Demo");
undoButton.setEnabled(false);
redoButton.setEnabled(false);
JPanel buttonPanel = new JPanel(new GridLayout());
buttonPanel.add(undoButton);
buttonPanel.add(redoButton);
getContentPane().add(buttonPanel, BorderLayout.NORTH);
getContentPane().add(canvas, BorderLayout.CENTER);
canvas.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
pointVector.addElement(point);
undoManager.undoableEditHappened(new UndoableEditEvent(
canvas, new UndoablePaintSquare(point, pointVector)));
undoButton.setText(undoManager.getUndoPresentationName());
redoButton.setText(undoManager.getRedoPresentationName());
undoButton.setEnabled(undoManager.canUndo());
redoButton.setEnabled(undoManager.canRedo());
canvas.repaint();
}
});
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
undoManager.undo();
} catch (CannotRedoException cre) {
cre.printStackTrace();
}
canvas.repaint();
undoButton.setEnabled(undoManager.canUndo());
redoButton.setEnabled(undoManager.canRedo());
}
});
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
undoManager.redo();
} catch (CannotRedoException cre) {
cre.printStackTrace();
}
canvas.repaint();
undoButton.setEnabled(undoManager.canUndo());
redoButton.setEnabled(undoManager.canRedo());
}
});
setSize(400, 300);
setVisible(true);
}
public static void main(String argv[]) {
new UndoManagerDemo();
}
class PaintCanvas extends JPanel {
private Vector points;
protected int width = 50;
protected int height = 50;
public PaintCanvas(Vector v) {
super();
points = v;
setOpaque(true);
setBackground(Color.white);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
for(int i=0;i<points.size();i++){
Point point = (Point) points.get(i);
g.drawRect(point.x, point.y, width, height);
}
}
}
class UndoablePaintSquare extends AbstractUndoableEdit {
protected Vector points;
protected Point point;
public UndoablePaintSquare(Point p, Vector v) {
points = v;
point = p;
}
public String getPresentationName() {
return "Square Addition";
}
public void undo() {
super.undo();
points.remove(point);
}
public void redo() {
super.redo();
points.add(point);
}
}
}
Undo redo textarea
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.UndoManager;
public class UndoRedoTextArea extends JFrame {
protected JTextArea textArea = new JTextArea();
protected UndoManager undoManager = new UndoManager();
protected JButton undoButton = new JButton("Undo");
protected JButton redoButton = new JButton("Redo");
public UndoRedoTextArea() {
super("Undo/Redo Demo");
undoButton.setEnabled(false);
redoButton.setEnabled(false);
JPanel buttonPanel = new JPanel(new GridLayout());
buttonPanel.add(undoButton);
buttonPanel.add(redoButton);
JScrollPane scroller = new JScrollPane(textArea);
getContentPane().add(buttonPanel, BorderLayout.NORTH);
getContentPane().add(scroller, BorderLayout.CENTER);
textArea.getDocument().addUndoableEditListener(
new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent e) {
undoManager.addEdit(e.getEdit());
updateButtons();
}
});
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
undoManager.undo();
} catch (CannotRedoException cre) {
cre.printStackTrace();
}
updateButtons();
}
});
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
undoManager.redo();
} catch (CannotRedoException cre) {
cre.printStackTrace();
}
updateButtons();
}
});
setSize(400, 300);
setVisible(true);
}
public void updateButtons() {
undoButton.setText(undoManager.getUndoPresentationName());
redoButton.setText(undoManager.getRedoPresentationName());
undoButton.setEnabled(undoManager.canUndo());
redoButton.setEnabled(undoManager.canRedo());
}
public static void main(String argv[]) {
new UndoRedoTextArea();
}
}