Java/Swing JFC/Customized Component — различия между версиями

Материал из Java эксперт
Перейти к: навигация, поиск
 
м (1 версия)
 
(нет различий)

Текущая версия на 06:44, 1 июня 2010

Alias Bean

/*
 * 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.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
class AliasBean extends JPanel {
  protected Vector aliVector;
  protected JList aliJList;
  private JTextField nameTF, addrTF;
  public AliasBean() {
    aliVector = new Vector();
    aliJList = new JList();
    // XXX MUST FIX THIS
    // aliJList.setSelectionMode(JList.SINGLE_SELECTION);
    aliJList.addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent evt) {
        int i = aliJList.getSelectedIndex();
        if (i < 0)
          return;
        Alias al = (Alias) aliVector.get(i);
        nameTF.setText(al.getName());
        addrTF.setText(al.getAddress());
      }
    });
    setLayout(new BorderLayout());
    add(BorderLayout.WEST, new JScrollPane(aliJList));
    JPanel rightPanel = new JPanel();
    add(BorderLayout.EAST, rightPanel);
    rightPanel.setLayout(new GridLayout(0, 1));
    JPanel buttons = new JPanel();
    rightPanel.add(buttons);
    buttons.setLayout(new GridLayout(0, 1, 15, 15));
    JButton b;
    buttons.add(b = new JButton("Set"));
    b.setToolTipText("Add or Change an alias");
    b.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        int i = aliJList.getSelectedIndex();
        if (i < 0) {
          // XXX error dialog??
          return;
        }
        setAlias(i, nameTF.getText(), addrTF.getText());
      }
    });
    buttons.add(b = new JButton("Delete"));
    b.setToolTipText("Delete the selected alias");
    b.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        int i = aliJList.getSelectedIndex();
        if (i < 0) {
          return;
        }
        deleteAlias(i);
      }
    });
    buttons.add(b = new JButton("Apply"));
    b.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        System.err.println("NOT WRITTEN YET");
      }
    });
    JPanel fields = new JPanel();
    rightPanel.add(fields);
    fields.setLayout(new GridLayout(2, 2));
    fields.add(new JLabel("Name"));
    fields.add(nameTF = new JTextField(10));
    fields.add(new JLabel("Address"));
    fields.add(addrTF = new JTextField(20));
  }
  public String expandAlias(String ali) {
    Alias a = findAlias(ali);
    if (a == null)
      return null;
    return a.getAddress();
  }
  public Alias findAlias(String ali) {
    for (int i = 0; i < aliVector.size(); i++) {
      Alias a = (Alias) aliVector.get(i);
      if (a.getName().equals(ali))
        return a;
    }
    return null; // not found
  }
  /** Add an Alias */
  public void addAlias(Alias a) {
    Alias al = findAlias(a.getName());
    if (al == null) {
      aliVector.addElement(a);
    } else {
      // aliVector.setElement(a); // XXX fuzzy
    }
    aliJList.setListData(aliVector);
  }
  /** Add an alias, by its constituent parts */
  public void addAlias(String nn, String addr) {
    addAlias(new Alias(nn, addr));
  }
  /** Replace an Alias */
  public void setAlias(int n, String nam, String addr) {
    // TODO find it, replace it, or add it.
    aliVector.setElementAt(new Alias(nam, addr), n);
    aliJList.setListData(aliVector);
  }
  public void deleteAlias(int i) {
    aliVector.removeElementAt(i);
    aliJList.setListData(aliVector);
  }
}
class Alias {
  /** The name for the alias */
  protected String name;
  /** The email address for this alias */
  protected String address;
  public Alias(String n, String addr) {
    name = n;
    address = addr;
  }
  public String toString() {
    return name + " = " + address;
  }
  /** Get name */
  public String getName() {
    return name;
  }
  /** Set name */
  public void setName(String name) {
    this.name = name;
  }
  /** Get address */
  public String getAddress() {
    return address;
  }
  /** Set address */
  public void setAddress(String address) {
    this.address = address;
  }
}
/**
 * Test for AliasBean.
 * 
 * @version $Id: AliasBeanTest.java,v 1.3 2004/02/09 03:33:48 ian Exp $
 */
public class AliasBeanTest extends JFrame {
  JButton quitButton;
  /** "main program" method - construct and show */
  public static void main(String[] av) {
    // create a JFrameDemo object, tell it to show up
    new AliasBeanTest().setVisible(true);
  }
  /** Construct the object including its GUI */
  public AliasBeanTest() {
    super("AliasBeanTest");
    Container cp = getContentPane();
    AliasBean ab = new AliasBean();
    cp.add(BorderLayout.CENTER, ab);
    ab.addAlias("ian-cvs", "ian@openbsd.org");
    ab.addAlias("ian-dos", "http://www.darwinsys.ru/");
    cp.add(BorderLayout.SOUTH, quitButton = new JButton("Exit"));
    quitButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        setVisible(false);
        dispose();
        System.exit(0);
      }
    });
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        setVisible(false);
        dispose();
        System.exit(0);
      }
    });
    pack();
  }
}





Customized component

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.Customizer;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Calendar;
import java.util.Date;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Clock extends JButton implements Customizer, Externalizable,
    Runnable {
  protected PropertyChangeSupport propertyChangeSupport;
  protected boolean isDigital = false;
  protected Calendar calendar = Calendar.getInstance();
  public Clock() {
    propertyChangeSupport = new PropertyChangeSupport(this);
    setBackground(Color.white);
    setForeground(Color.black);
    (new Thread(this)).start();
  }
  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeBoolean(isDigital);
    out.writeObject(getBackground());
    out.writeObject(getForeground());
    out.writeObject(getPreferredSize());
  }
  public void readExternal(ObjectInput in) throws IOException,
      ClassNotFoundException {
    setDigital(in.readBoolean());
    setBackground((Color) in.readObject());
    setForeground((Color) in.readObject());
    setPreferredSize((Dimension) in.readObject());
  }
  public Dimension getPreferredSize() {
    return new Dimension(50, 50);
  }
  public Dimension getMinimumSize() {
    return getPreferredSize();
  }
  public Dimension getMaximumSize() {
    return getPreferredSize();
  }
  public void setDigital(boolean digital) {
    propertyChangeSupport.firePropertyChange("digital", new Boolean(
        isDigital), new Boolean(digital));
    isDigital = digital;
    repaint();
  }
  public boolean getDigital() {
    return isDigital;
  }
  public void addPropertyChangeListener(PropertyChangeListener lst) {
    if (propertyChangeSupport != null)
      propertyChangeSupport.addPropertyChangeListener(lst);
  }
  public void removePropertyChangeListener(PropertyChangeListener lst) {
    if (propertyChangeSupport != null)
      propertyChangeSupport.removePropertyChangeListener(lst);
  }
  public void setObject(Object bean) {
  }
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Color colorRetainer = g.getColor();
    g.setColor(getBackground());
    g.fillRect(0, 0, getWidth(), getHeight());
    getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight());
    calendar.setTime(new Date()); // get current time
    int hrs = calendar.get(Calendar.HOUR_OF_DAY);
    int min = calendar.get(Calendar.MINUTE);
    g.setColor(getForeground());
    if (isDigital) {
      String time = "" + hrs + ":" + min;
      g.setFont(getFont());
      FontMetrics fm = g.getFontMetrics();
      int y = (getHeight() + fm.getAscent()) / 2;
      int x = (getWidth() - fm.stringWidth(time)) / 2;
      g.drawString(time, x, y);
    } else {
      int x = getWidth() / 2;
      int y = getHeight() / 2;
      int rh = getHeight() / 4;
      int rm = getHeight() / 3;
      double ah = ((double) hrs + min / 60.0) / 6.0 * Math.PI;
      double am = min / 30.0 * Math.PI;
      g.drawLine(x, y, (int) (x + rh * Math.sin(ah)), (int) (y - rh
          * Math.cos(ah)));
      g.drawLine(x, y, (int) (x + rm * Math.sin(am)), (int) (y - rm
          * Math.cos(am)));
    }
    g.setColor(colorRetainer);
  }
  public void run() {
    while (true) {
      repaint();
      try {
        Thread.sleep(30 * 1000);
      } catch (InterruptedException ex) {
        break;
      }
    }
  }
  public static void main(String[] a) {
    JFrame f = new JFrame();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    Clock c = new Clock();
    f.getContentPane().add("Center", c);
    f.pack();
    f.setSize(new Dimension(300, 300));
    f.show();
  }
}





Demonstrating the Box Component

import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Polygon;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class RedBlueBox extends JComponent {
  public void paintComponent(Graphics g) {
    Insets insets = getInsets();
    int endX = getWidth() - insets.right;
    int endY = getHeight() - insets.bottom;
    // get the top-left corner
    int x = insets.left;
    int y = insets.top;
    g.setColor(Color.RED);
    Polygon p = new Polygon();
    p.addPoint(x, y);
    p.addPoint(endX, y);
    p.addPoint(x, endY);
    g.fillPolygon(p);
    g.setColor(Color.BLUE);
    p.reset();
    p.addPoint(endX, y);
    p.addPoint(x, endY);
    p.addPoint(endX, endY);
    g.fillPolygon(p);
  }
  public static void main(String args[]) {
    JFrame frame = new JFrame();
    Container contentPane = frame.getContentPane();
    contentPane.setLayout(new GridLayout(0, 1));
    JComponent comp = new RedBlueBox();
    comp.setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, Color.PINK));
    contentPane.add(comp);
    comp = new RedBlueBox();
    contentPane.add(comp);
    frame.setSize(300, 200);
    frame.show();
  }
}





FontChooser dialog

/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// FontPicker.java
//A quick test of the FontChooser dialog. (see FontChooser.java)
//
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
public class FontPicker extends JFrame {
  Color c;
  public FontPicker() {
    super("JColorChooser Test Frame");
    setSize(200, 100);
    final JButton go = new JButton("Show FontChooser");
    go.addActionListener(new ActionListener() {
      final FontChooser chooser = new FontChooser(FontPicker.this);
      boolean first = true;
      public void actionPerformed(ActionEvent e) {
        chooser.setVisible(true);
        // If we got a real font choice, then update our go button
        if (chooser.getNewFont() != null) {
          go.setFont(chooser.getNewFont());
          go.setForeground(chooser.getNewColor());
        }
      }
    });
    getContentPane().add(go);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }
  public static void main(String args[]) {
    FontPicker fp = new FontPicker();
    fp.setVisible(true);
  }
}
//FontChooser.java
//A font chooser that allows users to pick a font by name, size, style, and
//color. The color selection is provided by a JColorChooser pane. This
//dialog builds an AttributeSet suitable for use with JTextPane.
//
class FontChooser extends JDialog implements ActionListener {
  JColorChooser colorChooser;
  JComboBox fontName;
  JCheckBox fontBold, fontItalic;
  JTextField fontSize;
  JLabel previewLabel;
  SimpleAttributeSet attributes;
  Font newFont;
  Color newColor;
  public FontChooser(Frame parent) {
    super(parent, "Font Chooser", true);
    setSize(450, 450);
    attributes = new SimpleAttributeSet();
    // Make sure that any way the user cancels the window does the right
    // thing
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        closeAndCancel();
      }
    });
    // Start the long process of setting up our interface
    Container c = getContentPane();
    JPanel fontPanel = new JPanel();
    fontName = new JComboBox(new String[] { "TimesRoman", "Helvetica",
        "Courier" });
    fontName.setSelectedIndex(1);
    fontName.addActionListener(this);
    fontSize = new JTextField("12", 4);
    fontSize.setHorizontalAlignment(SwingConstants.RIGHT);
    fontSize.addActionListener(this);
    fontBold = new JCheckBox("Bold");
    fontBold.setSelected(true);
    fontBold.addActionListener(this);
    fontItalic = new JCheckBox("Italic");
    fontItalic.addActionListener(this);
    fontPanel.add(fontName);
    fontPanel.add(new JLabel(" Size: "));
    fontPanel.add(fontSize);
    fontPanel.add(fontBold);
    fontPanel.add(fontItalic);
    c.add(fontPanel, BorderLayout.NORTH);
    // Set up the color chooser panel and attach a change listener so that
    // color
    // updates get reflected in our preview label.
    colorChooser = new JColorChooser(Color.black);
    colorChooser.getSelectionModel().addChangeListener(
        new ChangeListener() {
          public void stateChanged(ChangeEvent e) {
            updatePreviewColor();
          }
        });
    c.add(colorChooser, BorderLayout.CENTER);
    JPanel previewPanel = new JPanel(new BorderLayout());
    previewLabel = new JLabel("Here"s a sample of this font.");
    previewLabel.setForeground(colorChooser.getColor());
    previewPanel.add(previewLabel, BorderLayout.CENTER);
    // Add in the Ok and Cancel buttons for our dialog box
    JButton okButton = new JButton("Ok");
    okButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        closeAndSave();
      }
    });
    JButton cancelButton = new JButton("Cancel");
    cancelButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        closeAndCancel();
      }
    });
    JPanel controlPanel = new JPanel();
    controlPanel.add(okButton);
    controlPanel.add(cancelButton);
    previewPanel.add(controlPanel, BorderLayout.SOUTH);
    // Give the preview label room to grow.
    previewPanel.setMinimumSize(new Dimension(100, 100));
    previewPanel.setPreferredSize(new Dimension(100, 100));
    c.add(previewPanel, BorderLayout.SOUTH);
  }
  // Ok, something in the font changed, so figure that out and make a
  // new font for the preview label
  public void actionPerformed(ActionEvent ae) {
    // Check the name of the font
    if (!StyleConstants.getFontFamily(attributes).equals(
        fontName.getSelectedItem())) {
      StyleConstants.setFontFamily(attributes, (String) fontName
          .getSelectedItem());
    }
    // Check the font size (no error checking yet)
    if (StyleConstants.getFontSize(attributes) != Integer.parseInt(fontSize
        .getText())) {
      StyleConstants.setFontSize(attributes, Integer.parseInt(fontSize
          .getText()));
    }
    // Check to see if the font should be bold
    if (StyleConstants.isBold(attributes) != fontBold.isSelected()) {
      StyleConstants.setBold(attributes, fontBold.isSelected());
    }
    // Check to see if the font should be italic
    if (StyleConstants.isItalic(attributes) != fontItalic.isSelected()) {
      StyleConstants.setItalic(attributes, fontItalic.isSelected());
    }
    // and update our preview label
    updatePreviewFont();
  }
  // Get the appropriate font from our attributes object and update
  // the preview label
  protected void updatePreviewFont() {
    String name = StyleConstants.getFontFamily(attributes);
    boolean bold = StyleConstants.isBold(attributes);
    boolean ital = StyleConstants.isItalic(attributes);
    int size = StyleConstants.getFontSize(attributes);
    //Bold and italic don"t work properly in beta 4.
    Font f = new Font(name, (bold ? Font.BOLD : 0)
        + (ital ? Font.ITALIC : 0), size);
    previewLabel.setFont(f);
  }
  // Get the appropriate color from our chooser and update previewLabel
  protected void updatePreviewColor() {
    previewLabel.setForeground(colorChooser.getColor());
    // Manually force the label to repaint
    previewLabel.repaint();
  }
  public Font getNewFont() {
    return newFont;
  }
  public Color getNewColor() {
    return newColor;
  }
  public AttributeSet getAttributes() {
    return attributes;
  }
  public void closeAndSave() {
    // Save font & color information
    newFont = previewLabel.getFont();
    newColor = previewLabel.getForeground();
    // Close the window
    setVisible(false);
  }
  public void closeAndCancel() {
    // Erase any font information and then close the window
    newFont = null;
    newColor = null;
    setVisible(false);
  }
}





Oval Panel

import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class OvalPanel extends JPanel {
  Color color;
  public OvalPanel() {
    this(Color.black);
  }
  public OvalPanel(Color color) {
    this.color = color;
  }
  public void paintComponent(Graphics g) {
    int width = getWidth();
    int height = getHeight();
    g.setColor(color);
    g.drawOval(0, 0, width, height);
  }
  public static void main(String args[]) {
    JFrame frame = new JFrame("Oval Sample");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container content = frame.getContentPane();
    content.setLayout(new GridLayout(2, 2));
    Color colors[] = { Color.red, Color.blue, Color.green, Color.yellow };
    for (int i = 0; i < 4; i++) {
      OvalPanel panel = new OvalPanel(colors[i]);
      content.add(panel);
    }
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}





Ploygon Button

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JApplet;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JToolTip;
import javax.swing.Timer;
public class PolygonButton extends JComponent implements MouseListener,
    MouseMotionListener {
  static public Color ACTIVE_COLOR = Color.red;
  static public Color INACTIVE_COLOR = Color.darkGray;
  protected String text;
  protected Polygon polygon;
  protected Rectangle rectangle;
  protected boolean isActive;
  protected static PolygonButton button;
  public PolygonButton(Polygon p, String text) {
    polygon = p;
    setText(text);
    setOpaque(false);
    addMouseListener(this);
    addMouseMotionListener(this);
    rectangle = new Rectangle(polygon.getBounds()); // Bug alert!
    rectangle.grow(1, 1);
    setBounds(rectangle);
    polygon.translate(-rectangle.x, -rectangle.y);
  }
  public void setText(String t) {
    text = t;
  }
  public String getText() {
    return text;
  }
  public void mouseMoved(MouseEvent e) {
    if (!rectangle.contains(e.getX(), e.getY()) || e.isConsumed()) {
      if (isActive) {
        isActive = false;
        repaint();
      }
      return; // quickly return, if outside our rectangle
    }
    int x = e.getX() - rectangle.x;
    int y = e.getY() - rectangle.y;
    boolean active = polygon.contains(x, y);
    if (isActive != active)
      setState(active);
    if (active)
      e.consume();
  }
  public void mouseDragged(MouseEvent e) {
  }
  protected void setState(boolean active) {
    isActive = active;
    repaint();
    if (active) {
      if (button != null)
        button.setState(false);
      setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    } else {
      button = null;
      setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }
  }
  public void mouseClicked(MouseEvent e) {
  }
  public void mousePressed(MouseEvent e) {
  }
  public void mouseReleased(MouseEvent e) {
  }
  public void mouseExited(MouseEvent e) {
    mouseMoved(e);
  }
  public void mouseEntered(MouseEvent e) {
    mouseMoved(e);
  }
  public void paint(Graphics g) {
    g.setColor(isActive ? ACTIVE_COLOR : INACTIVE_COLOR);
    g.drawPolygon(polygon);
  }
  public static void main(String[] argv) {
    JFrame f = new JFrame();
    f.setSize(400, 300);
    Polygon p = new Polygon();
    p.addPoint(10, 10);
    p.addPoint(100, 300);
    p.addPoint(300, 300);
    p.addPoint(10, 10);
    PolygonButton btn = new PolygonButton(p, "button");
    f.getContentPane().add(btn);
    WindowListener wndCloser = new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    };
    f.addWindowListener(wndCloser);
    f.setVisible(true);
  }
}





The MyBean JavaBean Component

import java.awt.Point;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyBean {
  private String names[];
  private Point p;
  private int length;
  public String[] getNames() {
    return names;
  }
  public Point getPoint() {
    return p;
  }
  public int getLength() {
    return length;
  }
  public void setNames(String newValue[]) {
    names = newValue;
  }
  public void setPoint(Point newValue) {
    p = newValue;
  }
  public void setLength(int newValue) {
    length = newValue;
  }
  public static void main(String args[]) throws IOException {
    // Create
    MyBean saveme = new MyBean();
    saveme.setNames(new String[] { "one", "two", "three" });
    saveme.setPoint(new Point(15, 27));
    saveme.setLength(6);
    // Save
    XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(
        new FileOutputStream("saveme.xml")));
    encoder.writeObject(saveme);
    encoder.close();
  }
}





The TrafficLight Component

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditorSupport;
import java.beans.SimpleBeanInfo;
import java.util.TooManyListenersException;
import java.util.Vector;
import javax.swing.JComponent;
public class TrafficLight extends JComponent {
  public static String STATE_RED = "RED";
  public static String STATE_YELLOW = "YELLOW";
  public static String STATE_GREEN = "GREEN";
  private static int DELAY = 3000;
  private String defaultLightState;
  private String currentLightState;
  private boolean debug;
  private Thread runner;
  private transient ActionListener listener;
  public TrafficLight() {
    defaultLightState = currentLightState = STATE_RED;
    setPreferredSize(new Dimension(100, 200));
  }
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    // Paint the outline of the traffic light
    g.setColor(Color.white);
    g.fillRect(2, 2, 96, 196);
    // Debug
    if (debug) {
      System.out.println("Current light state is: " + currentLightState);
    }
    // Which light is on?
    if (currentLightState.equals(STATE_RED)) {
      g.setColor(Color.red);
      g.fillOval(30, 30, 40, 40);
    } else if (currentLightState.equals(STATE_YELLOW)) {
      g.setColor(Color.yellow);
      g.fillOval(30, 80, 40, 40);
    } else if (currentLightState.equals(STATE_GREEN)) {
      g.setColor(Color.green);
      g.fillOval(30, 130, 40, 40);
    }
  }
  public String getCurrentLightState() {
    return currentLightState;
  }
  public void setCurrentLightState(String currentLightState) {
    this.currentLightState = currentLightState;
    if (currentLightState != STATE_YELLOW) {
      if (debug) {
        System.out.println("Firing action event");
      }
      ActionEvent ae = new ActionEvent(this,
          ActionEvent.ACTION_PERFORMED, currentLightState);
      fireActionPerformed(ae);
    }
    repaint();
  }
  public void setDefaultLightState(String defaultLightState) {
    this.defaultLightState = defaultLightState;
    currentLightState = defaultLightState;
    repaint();
  }
  public String getDefaultLightState() {
    return defaultLightState;
  }
  public void setDebug(boolean debug) {
    this.debug = debug;
  }
  public boolean isDebug() {
    return debug;
  }
  public void initiate() {
    if (debug) {
      System.out.println("Initiate traffic light cycle!");
    }
    startCycle();
  }
  private void startCycle() {
    if (runner == null) {
      Runnable runnable = new Runnable() {
        public void run() {
          if (debug) {
            System.out.println("Started cycle");
          }
          while (runner != null) {
            try {
              Thread.sleep(DELAY);
            } catch (InterruptedException e) {
            }
            if (currentLightState.equals(STATE_RED)) {
              setCurrentLightState(STATE_GREEN);
            } else if (currentLightState.equals(STATE_GREEN)) {
              setCurrentLightState(STATE_YELLOW);
            } else {
              setCurrentLightState(STATE_RED);
            }
            if (currentLightState.equals(defaultLightState)) {
              runner = null;
            }
          }
        }
      };
      runner = new Thread(runnable);
      runner.start();
    }
  }
  public void lightChange(ActionEvent x) {
    String command = x.getActionCommand();
    if (debug) {
      System.out.println("Received event from traffic light: "
          + defaultLightState + " command: go to " + command);
    }
    if (command.equals(STATE_RED)) {
      if (!currentLightState.equals(STATE_GREEN)) {
        currentLightState = STATE_GREEN;
        repaint();
      }
    } else if (command.equals(STATE_GREEN)) {
      if (!currentLightState.equals(STATE_RED)) {
        currentLightState = STATE_YELLOW;
        repaint();
        try {
          Thread.sleep(DELAY);
        } catch (InterruptedException e) {
        }
        currentLightState = STATE_RED;
        repaint();
      }
    }
  }
  public synchronized void removeActionListener(ActionListener l) {
    if (debug) {
      System.out.println("Deregistering listener");
    }
    if (listener == l) {
      listener = null;
    }
  }
  public synchronized void addActionListener(ActionListener l)
      throws TooManyListenersException {
    if (debug) {
      System.out.println("Registering listener");
    }
    if (listener == null) {
      listener = l;
    } else {
      throw new TooManyListenersException();
    }
  }
  protected void fireActionPerformed(ActionEvent e) {
    if (debug) {
      System.out.println("Firing action event");
    }
    if (listener != null) {
      listener.actionPerformed(e);
    }
  }
}
class LightColorEditor extends PropertyEditorSupport {
  public String[] getTags() {
    String values[] = { TrafficLight.STATE_RED, TrafficLight.STATE_YELLOW,
        TrafficLight.STATE_GREEN };
    return values;
  }
}
class TrafficLightBeanInfo extends SimpleBeanInfo {
  public PropertyDescriptor[] getPropertyDescriptors() {
    try {
      PropertyDescriptor pd1 = new PropertyDescriptor("debug",
          TrafficLight.class);
      PropertyDescriptor pd2 = new PropertyDescriptor(
          "defaultLightState", TrafficLight.class);
      pd2.setPropertyEditorClass(LightColorEditor.class);
      PropertyDescriptor result[] = { pd1, pd2 };
      return result;
    } catch (IntrospectionException e) {
      System.err.println("Unexpected exception: " + e);
      return null;
    }
  }
}
class MyBean {
  private transient Vector actionListeners;
  public synchronized void removeActionListener(ActionListener l) {
    if (actionListeners != null && actionListeners.contains(l)) {
      Vector v = (Vector) actionListeners.clone();
      v.removeElement(l);
      actionListeners = v;
    }
  }
  public synchronized void addActionListener(ActionListener l) {
    Vector v = (actionListeners == null) ? new Vector(2)
        : (Vector) actionListeners.clone();
    if (!v.contains(l)) {
      v.addElement(l);
      actionListeners = v;
    }
  }
  protected void fireActionPerformed(ActionEvent e) {
    if (actionListeners != null) {
      Vector listeners = actionListeners;
      int count = listeners.size();
      for (int i = 0; i < count; i++) {
        ((ActionListener) listeners.elementAt(i)).actionPerformed(e);
      }
    }
  }
}