第6章 实用工具
Swing包括许多实用工具,本章将介绍这些实用工具。其中有些实用工具(如计时器和由SwingUtilties类提供的static方法)在Swing内部使用,而进度监视器和进度监视器流等其他的实用工具则不是内容使用的。使用Swing的开发人员可以使用本章介绍的所有实用工具。
6.1 计时器
例6-1 使用Swing计时器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
private int seconds=1;
public Test() {
Timer oneSecondTimer = new Timer(1000, this);
Timer timerWithInitialDelay = new Timer(2000,
new TimerWithDelayListener());
Timer oneTimeTimer = new Timer(10000,
new OneTimeListener());
timerWithInitialDelay.setInitialDelay(5000);
oneTimeTimer.setRepeats(false);
oneSecondTimer.start();
timerWithInitialDelay.start();
oneTimeTimer.start();
}
public void actionPerformed(ActionEvent e) {
if(seconds == 0)
System.out.println("Time: " + seconds + " second");
else
System.out.println("Time: " + seconds + " seconds");
seconds++;
}
public static void main(String args[]) {
new Test();
while(true);
}
}
class TimerWithDelayListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("Timer with Delay Ringing");
}
}
class OneTimeListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("One Time Timer Ringing");
}
}
例6-2 重载构造计时器时所指定的延迟
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
public Test() {
Timer oneSecondTimer = new Timer(1000, this);
oneSecondTimer.setInitialDelay(10000);
oneSecondTimer.setRepeats(false);
oneSecondTimer.start();
}
public void actionPerformed(ActionEvent e) {
System.out.println("ring ...");
}
public static void main(String args[]) {
new Test();
while(true);
}
}
例6-3 计时器日志
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
public Test() {
Timer.setLogTimers(true);
Timer oneSecondTimer = new MyTimer(1000, this);
oneSecondTimer.start();
}
public void actionPerformed(ActionEvent e) {
System.out.println("ring ...");
}
public static void main(String args[]) {
new Test();
while(true);
}
}
class MyTimer extends Timer {
public MyTimer(int delay, ActionListener listener) {
super(delay, listener);
}
public String toString() {
return "MyTimer";
}
}
例6-4 与单个计时器相关联的多个动作监听器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
private int seconds=1;
public Test() {
Timer oneSecondTimer = new Timer(1000, this);
oneSecondTimer.addActionListener(new SecondListener());
oneSecondTimer.addActionListener(new ThirdListener());
oneSecondTimer.start();
}
public void actionPerformed(ActionEvent e) {
if(seconds == 0)
System.out.println("Time: " + seconds + " second");
else
System.out.println("Time: " + seconds + " seconds");
seconds++;
}
public static void main(String args[]) {
new Test();
while(true);
}
}
class SecondListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("Second Listener");
}
}
class ThirdListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("Third Listener");
}
}
例6-5 合并计时器事件
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
private boolean firstRing = true;
private int ring = 1;
public Test() {
Timer.setLogTimers(true);
Timer oneSecondTimer = new Timer(1000, this);
// comment out the following line for colaescing
oneSecondTimer.setCoalesce(false);
System.out.println("Timer is coalescing: " +
oneSecondTimer.isCoalesce());
oneSecondTimer.start();
}
public void actionPerformed(ActionEvent e) {
System.out.println("ring #" + ring++);
if(firstRing) {
// simulate a time consuming operation by sleeping
// for 10 seconds ...
try {
Thread.currentThread().sleep(10000);
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
firstRing = false;
}
}
public static void main(String args[]) {
new Test();
while(true);
}
}
6.2 事件监听器列表
6.3 Swing实用工具
例6-6 计算两个矩形之间的差集、交集和并集
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JApplet {
Rectangle r1 = new Rectangle(20,20,150,75);
Rectangle r2 = new Rectangle(100,40,100,150);
Rectangle destination;
public Test() {
destination = new Rectangle(r2);
// print out the intersection of r1 and r2 ...
System.out.println("Intersection: " +
SwingUtilities.computeIntersection(r1.x,r1.y,
r1.width,r1.height,destination));
System.out.println();
// print out the union of r1 and r2 ...
System.out.println("Union: " +
SwingUtilities.computeUnion(r1.x,r1.y,
r1.width,r1.height,destination));
System.out.println();
// print out the difference of r1 and r2 ...
Rectangle[] difference =
SwingUtilities.computeDifference(r1, r2);
System.out.println("Difference:");
for(int i=0; i < difference.length; ++i) {
System.out.println(difference[i]);
}
}
public void paint(Graphics g) {
g.setColor(Color.red);
g.fillRect(r1.x, r1.y, r1.width, r1.height);
g.setColor(Color.yellow);
g.fillRect(r2.x, r2.y, r2.width, r2.height);
}
}
<applet archive="s06_tu02.jar" code="Test.class" width="600" height="550"><param name="height" value="550"> <param name="archive" value="s06_tu02.jar"> <param name="width" value="600"> <param name="code" value="Test.class"> <param name="codeBase" value="http://www.web.nyist.net/~rf/gui/"></applet>
图6-2 转换坐标系统
例6-7 转换鼠标坐标
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JApplet {
private Point lastScreenPt = null;
private final Container contentPane = getContentPane();
private PanelWithString
outer = new PanelWithString(Color.orange),
inner = new PanelWithString(Color.red),
innermost = new PanelWithString(Color.yellow);
public Test() {
Font font = new Font("Times-Roman", Font.ITALIC, 26);
contentPane.setLayout(new OverlayLayout(contentPane));
contentPane.add(innermost);
contentPane.add(inner);
contentPane.add(outer);
innermost.setMaximumSize(new Dimension(350,50));
inner.setMaximumSize(new Dimension(450,200));
outer.setMaximumSize(new Dimension(550,400));
setFont(font);
innermost.setFont(font);
inner.setFont(font);
outer.setFont(font);
contentPane.addMouseMotionListener(
new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
Point pt = e.getPoint();
outer.setString(SwingUtilities.convertPoint(
contentPane, pt, outer).toString());
inner.setString(SwingUtilities.convertPoint(
contentPane, pt, inner).toString());
innermost.setString(SwingUtilities.convertPoint(
contentPane, pt, innermost).toString());
SwingUtilities.convertPointToScreen(
pt, contentPane);
lastScreenPt = pt;
repaint();
}
});
}
public void paint(Graphics g) {
super.paint(g);
if(lastScreenPt != null) {
String s = new String("Screen: " + lastScreenPt);
g.setColor(getForeground());
g.drawString(s,10,g.getFontMetrics().getHeight());
SwingUtilities.convertPointFromScreen(lastScreenPt,
contentPane);
s = "Content Pane: " + lastScreenPt;
g.drawString(s,10,g.getFontMetrics().getHeight()*2);
}
else {
g.setColor(getForeground());
g.drawString("MOVE THE MOUSE IN HERE",10,
g.getFontMetrics().getHeight());
}
}
}
class PanelWithString extends JPanel {
String s;
Color color;
public PanelWithString(Color color) {
this.color = color;
}
public void setString(String s) {
this.s = s;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension size = getSize();
g.setColor(color);
g.fillRect(0,0,size.width,size.height);
if(s != null) {
g.setColor(getForeground());
g.drawString(s,10,g.getFontMetrics().getHeight());
}
}
}
6.4 Swing常量
6.5 Borlayout和Box类
6.5.1 BoxLayout类
<applet archive="s06_tu03.jar" code="Test.class" width="400" height="250"><param name="height" value="250"> <param name="archive" value="s06_tu03.jar"> <param name="width" value="400"> <param name="code" value="Test.class"> <param name="codeBase" value="http://www.web.nyist.net/~rf/gui/"></applet>
图6-3 两个使用BoxLayout的容器
例6-8 使用BoxLayout
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JApplet {
public Test() {
Container contentPane = getContentPane();
ContainerWithBoxLayout yaxis =
new ContainerWithBoxLayout(BoxLayout.Y_AXIS);
ContainerWithBoxLayout xaxis =
new ContainerWithBoxLayout(BoxLayout.X_AXIS);
contentPane.setLayout(new FlowLayout());
xaxis.add(new JButton(new ImageIcon("reach.gif")));
xaxis.add(new JButton(new ImageIcon("punch.gif")));
xaxis.add(new JButton(new ImageIcon("open_hand.gif")));
yaxis.add(new JButton(new ImageIcon("ladybug.gif")));
yaxis.add(new JButton(new ImageIcon("crab.gif")));
yaxis.add(new JButton(new ImageIcon("frog.gif")));
yaxis.add(new JButton(new ImageIcon("snail.gif")));
contentPane.add(xaxis);
contentPane.add(yaxis);
}
}
class ContainerWithBoxLayout extends JPanel {
public ContainerWithBoxLayout(int orientation) {
setLayout(new BoxLayout(this, orientation));
}
}
6.5.2 Box类
例6-9 使用水平和垂直的膨胀体
6.6 进度监视器
6.6.1 ProgressMonitor
图6-5 使用一个进度监视器(注:此为一可点击执行的.jar文件,但需要下载到你的电脑上方可点击执行)
例6-10 使用一个进度监视器
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class Test extends JFrame {
private JButton readButton = new JButton("read file");
private BufferedInputStream in;
private ProgressMonitor pm;
private String fileName = "Test.java";
public Test() {
final Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(readButton);
readButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
in = new BufferedInputStream(
new FileInputStream(fileName));
pm = new ProgressMonitor(contentPane,
"Reading File:",
fileName,
0, in.available());
}
catch(FileNotFoundException fnfx) {
fnfx.printStackTrace();
}
catch(IOException iox) {
iox.printStackTrace();
}
ReadThread t = new ReadThread();
t.start();
}
});
}
class ReadThread extends Thread {
int i, cnt=0;
String s;
public void run() {
try {
readButton.setEnabled(false);
while(!pm.isCanceled() && (i = in.read()) != -1) {
try {
Thread.currentThread().sleep(25);
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
System.out.print((char)i);
SwingUtilities.invokeLater(new Runnable(){
public void run() {
pm.setProgress(++cnt);
}
});
}
if(pm.isCanceled())
JOptionPane.showMessageDialog(
Test.this,
"Operation Canceled!",
"Cancellation",
JOptionPane.ERROR_MESSAGE);
}
catch(IOException ex) {
ex.printStackTrace();
}
finally {
try {
in.close();
}
catch(IOException ex2) {
ex2.printStackTrace();
}
}
readButton.setEnabled(true);
}
}
public static void main(String args[]) {
GJApp.launch(new Test(),
"Using Progress Monitors",300,300,450,300);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
6.6.2 PropressMonitorInputStream
例6-11 使用ProgressMonitorInputStream
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class Test extends JFrame {
private ProgressMonitorInputStream in;
private JButton readButton = new JButton("read file");
public Test() {
final Container contentPane = getContentPane();
final String fileName = "Test.java";
contentPane.setLayout(new FlowLayout());
contentPane.add(readButton);
readButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
in = new ProgressMonitorInputStream(
contentPane,
"Reading " + fileName,
new FileInputStream(fileName));
}
catch(FileNotFoundException ex) {
ex.printStackTrace();
}
ReadThread t = new ReadThread();
readButton.setEnabled(false);
t.start();
}
});
}
class ReadThread extends Thread {
public void run() {
int i;
try {
while((i = in.read()) != -1) {
System.out.print((char)i);
try {
Thread.currentThread().sleep(10);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
in.close();
}
catch(IOException ex) {
JOptionPane.showMessageDialog(
Test.this,
"Operation Canceled!",
"Cancellation",
JOptionPane.ERROR_MESSAGE);
}
readButton.setEnabled(true);
}
}
public static void main(String args[]) {
GJApp.launch(new Test(),
"Using ProgressMonitorInputStream",
300,300,450,300);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
6.7 撤消/重复
6.7.1一个简单的撤消/重复样例
例6-12 一个简单的撤消/重复样例
import javax.swing.*;
import javax.swing.undo.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JApplet {
private JPanel colorPanel = new JPanel();
private BackgroundColorEdit undo = new BackgroundColorEdit();
private Color oldColor;
public void init() {
colorPanel.setBorder(
BorderFactory.createTitledBorder(
"Change color and subsequently undo " +
"from the Edit menu"));
makeMenuBar();
getContentPane().add(colorPanel, BorderLayout.CENTER);
}
private void makeMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu editMenu = new JMenu("Edit");
editMenu.add(new SetColorAction());
editMenu.add(new UndoAction());
menuBar.add(editMenu);
setJMenuBar(menuBar);
}
class SetColorAction extends AbstractAction {
public SetColorAction() {
super("Set color ...");
}
public void actionPerformed(ActionEvent e) {
Color color = JColorChooser.showDialog(
Test.this, // parent component
"Pick A Color", // dialog title
null); // initial color
if(color != null) {
oldColor = colorPanel.getBackground();
colorPanel.setBackground(color);
}
}
}
class UndoAction extends AbstractAction {
public UndoAction() {
putValue(Action.NAME, undo.getUndoPresentationName());
}
public void actionPerformed(ActionEvent e) {
String name = (String)getValue(Action.NAME);
boolean isUndo = name.equals(
undo.getUndoPresentationName());
if(isUndo) {
undo.undo();
putValue(Action.NAME,
undo.getRedoPresentationName());
}
else {
undo.redo();
putValue(Action.NAME,
undo.getUndoPresentationName());
}
}
}
class BackgroundColorEdit extends AbstractUndoableEdit {
public void undo() throws CannotUndoException {
super.undo();
toggleColor();
}
public void redo() throws CannotRedoException {
super.redo();
toggleColor();
}
public String getUndoPresentationName() {
return "Undo";
}
public String getRedoPresentationName() {
return "Redo";
}
private void toggleColor() {
Color color = colorPanel.getBackground();
colorPanel.setBackground(oldColor);
oldColor = color;
}
}
}
6.7.2 UndoableEditSupport
例6-13 使用UndoableEditSupport
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JApplet {
private ColorPanel colorPanel = new ColorPanel();
private UndoAction undoAction = new UndoAction();
public void init() {
colorPanel.setBorder(
BorderFactory.createTitledBorder(
"Change color and subsequently undo " +
"from the Edit menu"));
makeMenuBar();
colorPanel.addUndoableEditListener(undoAction);
getContentPane().add(colorPanel, BorderLayout.CENTER);
}
private void makeMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu editMenu = new JMenu("Edit");
editMenu.add(new SetColorAction());
editMenu.add(undoAction);
menuBar.add(editMenu);
setJMenuBar(menuBar);
}
class UndoAction extends AbstractAction
implements UndoableEditListener {
UndoableEdit lastEdit;
public UndoAction() {
putValue(Action.NAME, "Undo");
setEnabled(false);
}
public void actionPerformed(ActionEvent e) {
String name = (String)getValue(Action.NAME);
boolean isUndo = name.equals(
lastEdit.getUndoPresentationName());
if(isUndo) {
lastEdit.undo();
putValue(Action.NAME,
lastEdit.getRedoPresentationName());
}
else {
lastEdit.redo();
putValue(Action.NAME,
lastEdit.getUndoPresentationName());
}
}
public void undoableEditHappened(UndoableEditEvent e) {
lastEdit = e.getEdit();
putValue(Action.NAME,
lastEdit.getUndoPresentationName());
if(lastEdit.canUndo())
setEnabled(true);
}
}
class SetColorAction extends AbstractAction {
public SetColorAction() {
super("Set color ...");
}
public void actionPerformed(ActionEvent e) {
Color color = JColorChooser.showDialog(
Test.this, // parent component
"Pick A Color", // dialog title
null); // initial color
if(color != null) {
colorPanel.setBackground(color);
}
}
}
}
class ColorPanel extends JPanel {
UndoableEditSupport support;
BackgroundColorEdit edit = new BackgroundColorEdit();
Color oldColor;
public void addUndoableEditListener(
UndoableEditListener l) {
support.addUndoableEditListener(l);
}
public void removeUndoableEditListener(
UndoableEditListener l) {
support.removeUndoableEditListener(l);
}
public void setBackground(Color color) {
oldColor = getBackground();
super.setBackground(color);
if(support == null)
support = new UndoableEditSupport();
support.postEdit(edit);
}
class BackgroundColorEdit extends AbstractUndoableEdit {
public void undo() throws CannotUndoException {
super.undo();
toggleColor();
}
public void redo() throws CannotRedoException {
super.redo();
toggleColor();
}
public String getUndoPresentationName() {
return "Undo Background Color Change";
}
public String getRedoPresentationName() {
return "Redo Background Color Change";
}
private void toggleColor() {
Color color = getBackground();
setBackground(oldColor);
oldColor = color;
}
}
}
6.7.3组合编辑
例6-14 使用组合编辑
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JApplet {
private UndoableList list = new UndoableList();
private JScrollPane scrollPane = new JScrollPane(list);
private JButton addButton = new JButton("Add Item"),
endButton = new JButton("End"),
undoButton = new JButton("Undo");
private UndoAction undoAction = new UndoAction();
private CompoundEdit compoundEdit = new CompoundEdit();
private int cnt=0;
public void init() {
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(addButton);
contentPane.add(endButton);
contentPane.add(undoButton);
contentPane.add(scrollPane);
scrollPane.setPreferredSize(new Dimension(150,150));
list.addUndoableEditListener(undoAction);
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
compoundEdit.end();
updateButtonsEnabledState();
}
});
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
list.undoableAdd("item #" + cnt++);
updateButtonsEnabledState();
}
});
undoButton.addActionListener(undoAction);
endButton.setEnabled(false);
undoButton.setEnabled(false);
}
private void updateButtonsEnabledState() {
boolean inProgress = compoundEdit.isInProgress();
endButton.setEnabled(inProgress);
addButton.setEnabled(inProgress);
if(undoButton.getText().equals("Undo"))
undoButton.setEnabled(compoundEdit.canUndo());
else
undoButton.setEnabled(compoundEdit.canRedo());
}
class UndoAction extends AbstractAction
implements UndoableEditListener {
public UndoAction() {
putValue(Action.NAME, "Undo");
}
public void actionPerformed(ActionEvent e) {
String name = undoButton.getText();
boolean isUndo = name.equals("Undo");
if(isUndo) compoundEdit.undo();
else compoundEdit.redo();
undoButton.setText(isUndo ? "Redo" : "Undo");
}
public void undoableEditHappened(UndoableEditEvent e) {
UndoableEdit edit = e.getEdit();
compoundEdit.addEdit(edit);
endButton.setEnabled(true);
}
}
}
class UndoableList extends JList {
UndoableEditSupport support = new UndoableEditSupport();
DefaultListModel model;
public UndoableList() {
setModel(model = new DefaultListModel());
}
public void addUndoableEditListener(UndoableEditListener l) {
support.addUndoableEditListener(l);
}
public void removeUndoableEditListener(
UndoableEditListener l) {
support.removeUndoableEditListener(l);
}
public void undoableAdd(Object s) {
model.addElement(s);
support.postEdit(new AddItemEdit());
}
class AddItemEdit extends AbstractUndoableEdit {
Object lastItemAdded;
public void undo() throws CannotUndoException {
super.undo();
lastItemAdded = model.getElementAt(model.getSize()-1);
model.removeElement(lastItemAdded);
}
public void redo() throws CannotRedoException {
super.redo();
model.addElement(lastItemAdded);
}
}
}
6.7.4 UndoManager
6.7.5状态编辑
例6-15 使用状态编辑
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Test extends JApplet {
private TextFieldPanel panel = new TextFieldPanel();
private StateEdit stateEdit;
private JButton startButton = new JButton("Start Edit"),
endButton = new JButton("End Edit"),
undoButton = new JButton("Undo");
public void init() {
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(startButton);
contentPane.add(endButton);
contentPane.add(undoButton);
contentPane.add(panel);
endButton.setEnabled(false);
undoButton.setEnabled(false);
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stateEdit = new StateEdit(panel);
endButton.setEnabled(true);
startButton.setEnabled(false);
}
});
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stateEdit.end();
undoButton.setEnabled(true);
endButton.setEnabled(false);
}
});
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String name = undoButton.getText();
boolean isUndo = name.equals("Undo");
if(isUndo) stateEdit.undo();
else stateEdit.redo();
undoButton.setText(isUndo ? "Redo" : "Undo");
}
});
}
}
class TextFieldPanel extends JPanel implements StateEditable {
JTextField[] fields = new JTextField[] {
new JTextField("text field 1"),
new JTextField("text field 2"),
new JTextField("text field 3"),
new JTextField("text field 4"),
};
public TextFieldPanel() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
for(int i=0; i < fields.length; ++i)
add(fields[i]);
}
public void storeState(Hashtable hashtable) {
for(int i=0; i < fields.length; ++i)
hashtable.put(fields[i], fields[i].getText());
}
public void restoreState(Hashtable hashtable) {
Enumeration keys = hashtable.keys();
while(keys.hasMoreElements()) {
JTextField field = (JTextField)keys.nextElement();
field.setText((String)hashtable.get(field));
}
}
}
6.8 本章回顾