OurButton Color-Annotated Source


This example illustrates how to implement both an event listener and event source.



package sunw.demo.buttons;

import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.Serializable;
import java.util.Vector;


/**
 * A simple Java Beans button.  OurButton is a "from-scratch" 
 * GUI component that's derived from Canvas.  It's a good example of
 * how to implement bound properties and support for event listeners.
 *
 * Parts of the source are derived from sun.awt.tint.TinyButtonPeer.
 */
public class OurButton extends Canvas implements Serializable,
				MouseListener, MouseMotionListener {

    /**
     * Constructs a Button with the a default label.
     */
    public OurButton() {
	this("press");
    }

    /**
     * Constructs a Button with the specified label.
     * @param label the label of the button
     */
    public OurButton(String label) {
	super();
	this.label = label;
	setFont(new Font("Dialog", Font.PLAIN, 12));
	setBackground(Color.lightGray);
	addMouseListener(this);
	addMouseMotionListener(this);
    }

    //----------------------------------------------------------------------

    /**
     * Paint the button: the label is centered in both dimensions.
     * 
     */
    public synchronized void paint(Graphics g) {
	int width = getSize().width;
	int height = getSize().height;

	g.setColor(getBackground());
	g.fill3DRect(0, 0, width - 1, height - 1, !down);

	g.setColor(getForeground());
	g.setFont(getFont());

	g.drawRect(2, 2, width - 4, height - 4);

	FontMetrics fm = g.getFontMetrics();
	g.drawString(label, (width - fm.stringWidth(label)) / 2, 
		          (height + fm.getMaxAscent() - fm.getMaxDescent()) / 2);
    }	

    //----------------------------------------------------------------------

    // Mouse listener methods.


    public void mouseClicked(MouseEvent evt) {
    }

    public void mousePressed(MouseEvent evt) {
	if (!isEnabled()) {
	    return;
	}
	down = true;
	repaint();
    }

    public void mouseReleased(MouseEvent evt) {
	if (!isEnabled()) {
	    return;
	}
	if (down) {
	    fireAction();
	    down = false;
	    repaint();
	}
    }

    public void mouseEntered(MouseEvent evt) {
    }

    public void mouseExited(MouseEvent evt) {
    }

    public void mouseDragged(MouseEvent evt) {
	if (!isEnabled()) {
	    return;
	}
	// Has the mouse been dragged outside the button?
	int x = evt.getX();
	int y = evt.getY();
	int width = getSize().width;
	int height = getSize().height;
	if (x < 0 || x > width || y < 0 || y > height) {
	    // Yes, we should deactivate any pending click.
	    if (down) {
		down = false;
		repaint();
	    }
	} else if (!down) {
	    down = true;
	    repaint();
	}
    }

    public void mouseMoved(MouseEvent evt) {
    }


    //----------------------------------------------------------------------

    // Methods for registering/deregistering event listeners

    /**
     * The specified ActionListeners actionPerformed method will 
     * be called each time the button is clicked.  The ActionListener
     * object is added to a list of ActionListeners managed by 
     * this button, it can be removed with removeActionListener.
     * Note: the JavaBeans specification does not require ActionListeners
     * to run in any particular order.
     * 
     * @see #removeActionListener
     * @param l the ActionListener
     */      

    public synchronized void addActionListener(ActionListener l) {
	pushListeners.addElement(l);
    }

    /** 
     * Remove this ActionListener from the buttons internal list.  If the
     * ActionListener isn't on the list, silently do nothing.
     * 
     * @see #addActionListener
     * @param l the ActionListener
     */      

    public synchronized void removeActionListener(ActionListener l) {
	pushListeners.removeElement(l);
    }


    /**
     * The specified PropertyChangeListeners propertyChange method will
     * be called each time the value of any bound property is changed.
     * The PropertyListener object is addded to a list of PropertyChangeListeners
     * managed by this button, it can be removed with removePropertyChangeListener.
     * Note: the JavaBeans specification does not require PropertyChangeListeners
     * to run in any particular order.
     *
     * @see #removePropertyChangeListener
     * @param l the PropertyChangeListener
     */      
    public void addPropertyChangeListener(PropertyChangeListener l) {
	changes.addPropertyChangeListener(l);
    }

    /** 
     * Remove this PropertyChangeListener from the buttons internal list.  
     * If the PropertyChangeListener isn't on the list, silently do nothing.
     * 
     * @see #addPropertyChangeListener
     * @param l the PropertyChangeListener
     */      
    public void removePropertyChangeListener(PropertyChangeListener l) {
	changes.removePropertyChangeListener(l);
    }

    //----------------------------------------------------------------------


    /** 
     * This method has the same effect as pressing the button.
     * 
     * @see #addActionListener
     */      

    public void fireAction() {
	if (debug) {
	    System.err.println("Button " + getLabel() + " pressed.");
	}
	Vector targets;
	synchronized (this) {
	    targets = (Vector) pushListeners.clone();
	}
	ActionEvent actionEvt = new ActionEvent(this, 0, null);
	for (int i = 0; i < targets.size(); i++) {
	    ActionListener target = (ActionListener)targets.elementAt(i);
	    target.actionPerformed(actionEvt);
	}

    }

    /** 
     * Enable debugging output.  Currently a message is printed each time
     * the button is clicked.  This is a bound property.
     * 
     * @see #getDebug
     * @see #addPropertyChangeListener
     */      
    public void setDebug(boolean x) {
	boolean old = debug;
	debug = x;
	changes.firePropertyChange("debug", new Boolean(old), new Boolean(x));
    }

    /** 
     * Returns true if debugging output is enabled.  
     * 
     * @see #setDebug
     */
    public boolean getDebug() {
	return debug;
    }

    /** 
     * Set the font size to 18 if true, 12 otherwise.  This property overrides
     * the value specified with setFontSize.  This is a bound property.
     * 
     * @see #isLargeFont
     * @see #addPropertyChangeListener
     */      
    public void setLargeFont(boolean b) {
	if (isLargeFont() == b) {
	    return;
	}
	int size = 12;
	if (b) {
	   size = 18;
	}
	Font old = getFont();
	setFont(new Font(old.getName(), old.getStyle(), size));
	changes.firePropertyChange("largeFont", new Boolean(!b), new Boolean(b));
    }

    /** 
     * Returns true if the font is "large" in the sense defined by setLargeFont.
     * 
     * @see #setLargeFont
     * @see #setFont
     */      
    public boolean isLargeFont() {
        if (getFont().getSize() >= 18) {
	    return true;
	} else {
	    return false;
	}
    }


   /** 
     * Set the point size of the current font.  This is a bound property.
     * 
     * @see #getFontSize
     * @see #setFont
     * @see #setLargeFont
     * @see #addPropertyChangeListener
     */      
    public void setFontSize(int x) {
	Font old = getFont();
	setFont(new Font(old.getName(), old.getStyle(), x));
	changes.firePropertyChange("fontSize", new Integer(old.getSize()), new Integer(x));
    }

    /** 
     * Return the current font point size.
     * 
     * @see #setFontSize
     */
    public int getFontSize() {
         return getFont().getSize();
    }

    /**
     * Set the current font and change its size to fit.  This is a 
     * bound property.
     *
     * @see #setFontSize
     * @see #setLargeFont
     */
    public void setFont(Font f) {
	Font old = getFont();
	super.setFont(f);
	sizeToFit();
	changes.firePropertyChange("font", old, f);
    }

    /** 
     * Set the buttons label and change it's size to fit.  This is a 
     * bound property.
     * 
     * @see #getLabel
     */
    public void setLabel(String newLabel) {
	String oldLabel = label;
	label = newLabel;
	sizeToFit();
	changes.firePropertyChange("label", oldLabel, newLabel);
    }

    /**
     * Returns the buttons label.
     * 
     * @see #setLabel
     */
    public String getLabel() {
	return label;
    }

    public Dimension getPreferredSize() {
	FontMetrics fm = getFontMetrics(getFont());
	return new Dimension(fm.stringWidth(label) + TEXT_XPAD, 
			     fm.getMaxAscent() + fm.getMaxDescent() + TEXT_YPAD);
    }

    /**
     * @deprecated provided for backward compatibility with old layout managers.
     */
    public Dimension preferredSize() {
	return getPreferredSize();
    }

    public Dimension getMinimumSize() {
	return getPreferredSize();
    }

    /**
     * @deprecated provided for backward compatibility with old layout managers.
     */
    public Dimension minimumSize() {
	return getMinimumSize();
    }

    private void sizeToFit() {
	Dimension d = getPreferredSize();
	setSize(d.width, d.height);
	Component p = getParent();
	if (p != null) {
	    p.invalidate();
	    p.doLayout();
	}
    }

    /**
     * Set the color the buttons label is drawn with.  This is a bound property.
     */
    public void setForeground(Color c) {
	Color old = getForeground();
	super.setForeground(c);
	changes.firePropertyChange("foreground", old, c);
    }


    /**
     * Set the color the buttons background is drawn with.  This is a bound property.
     */
    public void setBackground(Color c) {
	Color old = getBackground();
	super.setBackground(c);
	changes.firePropertyChange("background", old, c);
    }


    private boolean debug;
    private PropertyChangeSupport changes = new PropertyChangeSupport(this);
    private Vector pushListeners = new Vector();
    private String label;
    private boolean down;
    private boolean sized;

    static final int TEXT_XPAD = 12;
    static final int TEXT_YPAD = 8;
}

Java, JavaBeans, and JavaSoft are trademarks of Sun Microsystems Inc.

Copyright © 1996 Sun Microsystems, Inc., 2550 Garcia Ave., Mtn. View, CA 94043-1100 USA.
All rights reserved.