Commit e43ae211 authored by Daniel Vogel's avatar Daniel Vogel

add undo demo

parent b6d3d4a6
// CS 349 Undo Demo
import javax.swing.*;
import javax.swing.event.UndoableEditEvent;
import javax.swing.undo.UndoManager;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.*;
public class Main {
Model model;
public static void main(String[] args) {
new Main();
}
public Main() {
JFrame frame = new JFrame("UndoDemo");
// create Model and initialize it
// (value, min, max in this model)
model = new Model(22, 0, 100);
// create View
View view = new View(model);
// create Menu View
MainMenuView menuView = new MainMenuView(model);
// add views to the window
frame.getContentPane().add(view);
frame.setJMenuBar(menuView);
frame.setPreferredSize(new Dimension(500, 120));
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
// let all the views know that they're connected to the model
model.updateViews();
}
}
// CS 349 Undo Demo
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
// a main menu view
public class MainMenuView extends JMenuBar implements Observer {
// Undo menu items
private JMenuItem undoMenuItem;
private JMenuItem redoMenuItem;
// the model that this view is showing
private Model model;
public MainMenuView(Model model_) {
// set the model
model = model_;
model.addObserver(this);
// create a menu UI with undo/redo
JMenu fileMenu = new JMenu("File");
JMenu editMenu = new JMenu("Edit");
this.add(fileMenu);
this.add(editMenu);
// Create a "quit" menu item and add it to the file menu
JMenuItem quitMenuItem = new JMenuItem("Quit");
fileMenu.add(quitMenuItem);
// quit menu controller
quitMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
});
// create undo and redo menu items
undoMenuItem = new JMenuItem("Undo");
undoMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z,
ActionEvent.CTRL_MASK));
redoMenuItem = new JMenuItem("Redo");
redoMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y,
ActionEvent.CTRL_MASK));
editMenu.add(undoMenuItem);
editMenu.add(redoMenuItem);
// controllers for undo menu item
undoMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
model.undo();
}
});
// controller for redo menu item
redoMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
model.redo();
}
});
}
@Override
public void update(Observable arg0, Object arg1) {
undoMenuItem.setEnabled(model.canUndo());
redoMenuItem.setEnabled(model.canRedo());
}
}
// CS 349 Undo Demo
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.util.Observable;
import javax.swing.undo.*;
// A simple model that is undoable
public class Model extends Observable {
// Undo manager
private UndoManager undoManager;
// Model data
private int value;
private int min;
private int max;
Model(int value, int min, int max) {
undoManager = new UndoManager();
this.value = value;
this.min = min;
this.max = max;
}
public void updateViews() {
setChanged();
notifyObservers();
}
public int getValue() {
return value;
}
public void setValue(int v) {
System.out.println("Model: set value to " + v);
// create undoable edit
UndoableEdit undoableEdit = new AbstractUndoableEdit() {
// capture variables for closure
final int oldValue = value;
final int newValue = v;
// Method that is called when we must redo the undone action
public void redo() throws CannotRedoException {
super.redo();
value = newValue;
System.out.println("Model: redo value to " + value);
setChanged();
notifyObservers();
}
public void undo() throws CannotUndoException {
super.undo();
value = oldValue;
System.out.println("Model: undo value to " + value);
setChanged();
notifyObservers();
}
};
// Add this undoable edit to the undo manager
undoManager.addEdit(undoableEdit);
// finally, set the value and notify views
value = v;
setChanged();
notifyObservers();
}
public void incrementValue() {
System.out.println("Model: increment value ");
// constrain value to valid range
if (value + 1 > max) return;
// create undoable edit
UndoableEdit undoableEdit = new AbstractUndoableEdit() {
// Method that is called when we must redo the undone action
public void redo() throws CannotRedoException {
super.redo();
value = value + 1;
System.out.println("Model: redo value to " + value);
setChanged();
notifyObservers();
}
public void undo() throws CannotUndoException {
super.undo();
value = value - 1;
System.out.println("Model: undo value to " + value);
setChanged();
notifyObservers();
}
};
// Add this undoable edit to the undo manager
undoManager.addEdit(undoableEdit);
value = value + 1;
setChanged();
notifyObservers();
}
public void decrementValue() {
System.out.println("Model: decrement value ");
// constrain value to valid range
if (value - 1 < min) return;
// create undoable edit
UndoableEdit undoableEdit = new AbstractUndoableEdit() {
// Method that is called when we must redo the undone action
public void redo() throws CannotRedoException {
super.redo();
value = value - 1;
System.out.println("Model: redo value to " + value);
setChanged();
notifyObservers();
}
public void undo() throws CannotUndoException {
super.undo();
value = value + 1;
System.out.println("Model: undo value to " + value);
setChanged();
notifyObservers();
}
};
// Add this undoable edit to the undo manager
undoManager.addEdit(undoableEdit);
value = value - 1;
setChanged();
notifyObservers();
}
// could make these settable and undoable too
public int getMin() { return min; }
public int getMax() { return max; }
// undo and redo methods
// - - - - - - - - - - - - - -
public void undo() {
if (canUndo())
undoManager.undo();
}
public void redo() {
if (canRedo())
undoManager.redo();
}
public boolean canUndo() {
return undoManager.canUndo();
}
public boolean canRedo() {
return undoManager.canRedo();
}
}
// CS 349 Undo Demo
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.UndoableEdit;
import java.awt.*;
import java.awt.event.*;
import java.util.Observable;
import java.util.Observer;
class View extends JPanel implements Observer {
// the view's main user interface
private JSlider slider;
private JTextField text;
private JButton increment;
private JButton decrement;
// the model that this view is showing
private Model model;
View(Model model_) {
// set the model
model = model_;
model.addObserver(this);
// create the view UI
this.setLayout(new FlowLayout());
// slider to choose exact value
slider = new JSlider();
this.add(slider);
// text boc to change value
text = new JTextField("X", 4);
this.add(text);
// increment/decrement buttons
increment = new JButton("+");
decrement = new JButton("-");
this.add(increment);
this.add(decrement);
this.add(new JLabel("shortcut keys: CTRL-Z to undo, CTRL-Y to redo"));
// change the flag and see what happens
final boolean noChunking = false;
if (noChunking) {
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent arg0) {
model.setValue(slider.getValue());
}
});
} else {
// controller for when a drag event finishes
// this is the right undo "chunk"
slider.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
model.setValue(slider.getValue());
}
});
}
// add a controller for text edits too
// (will only fire when enter is pressed after editing ...)
text.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
model.setValue(Integer.parseInt(text.getText()));
} catch (NumberFormatException ex) {
// not a number, just update views to reset it
// (need to be careful here not to insert an undo)
model.updateViews();
}
}
});
increment.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
model.incrementValue();
}
});
decrement.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
model.decrementValue();
}
});
}
// Observer interface
@Override
public void update(Observable arg0, Object arg1) {
System.out.println("View: update");
slider.setValue(model.getValue());
slider.setMinimum(model.getMin());
slider.setMaximum(model.getMax());
text.setText(Integer.toString(model.getValue()));
}
}
# super simple makefile
# call it using 'make NAME=name_of_code_file_without_extension'
# (assumes a .java extension)
NAME = "Main"
all:
@echo "Compiling..."
javac *.java
run: all
@echo "Running..."
java $(NAME)
clean:
rm -rf *.class
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment