IncdecApp4: Incdec.java

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;

public class Incdec extends JPanel implements ActionListener, Adjustable { //*1 Catches ActionListener, Sends Adjustable
    /**
     * Our internal components that we need to remember
     */
    protected JButton upButton, downButton;
    protected JLabel label;

    /**
     * Our data, initialized inline here 
     */
    protected int value = 0;
    protected int min = 0;
    protected int max = 100;
    protected int incr = 1;

    public Incdec () {
	// Put a border on our JPanel
	// default color, user can modify later
	setBorder (new LineBorder(Color.RED, 1));

	// Use vertical grid layout to hold our buttons and stuff
	setLayout (new GridLayout (3, 1));
	
	// Our internal widgets:
	// Our up button
	upButton = new JButton ("+");
	upButton.addActionListener (this); //*2 Our internal callbacks
	add (upButton);

	// Our label widget
	label = new JLabel ();
	label.setHorizontalAlignment (JLabel.CENTER);
	refreshLabel ();
	add (label);

	// Our down button
	downButton = new JButton ("-");
	downButton.addActionListener (this); //*2
	add (downButton);
    }

    /**
     * Common callback for both internal buttons,
     * we use ivar to disambiguate.
     * Then we fire the result to *our* listeners.
     */
    public void actionPerformed (ActionEvent e) { //*2
	int type = 0;

        if (e.getSource()==upButton) { //*3 Create and fire our event (listenerList mechanism is inherited from JComponent)
	    value += incr; //*3
	    type = AdjustmentEvent.UNIT_INCREMENT; //*3
	}
	else if (e.getSource()==downButton) {
	    value -= incr;
	    type = AdjustmentEvent.UNIT_DECREMENT;
	}

	// Clamp at bounds
	if (value > max) value = max;
	if (value < min) value = min;

	// Update our label widget to match
	refreshLabel ();

	// Make a new event with our new data
	AdjustmentEvent event = new AdjustmentEvent (this, //*3
	    AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, type, value); //*3

	// Send it to each of *our* listeners
	for (AdjustmentListener l: //*3
	    listenerList.getListeners (AdjustmentListener.class)) { //*3
		l.adjustmentValueChanged (event); //*3
	} //*3

    }

    /**
     * Common code fragment, extracted to here
     */
    protected void refreshLabel() {
	label.setText (String.valueOf (value));
    }

    /**
     * Just as an example, we let user customize border color here
     */
    public void setBorderColor (Color color) {
	setBorder (new LineBorder(color, 1));
    }

    /**
     * Methods required by Adjustable,
     * listenerList is an ivar of JComponent, we access it here
     */
    public void addAdjustmentListener(AdjustmentListener l) { //*4 Required by Adjustable, add/remove listener
	listenerList.add (AdjustmentListener.class, l); //*4
    }
    public void removeAdjustmentListener(AdjustmentListener l) { //*4
	listenerList.remove (AdjustmentListener.class, l); //*4
    }

    /**
     * Methods required by Adjustable,
     * though block vs. unit and visibleAmount don't really make sense for us 
     */
    public int getValue() { return value; } //*5 Required by Adjustable, do something reasonable
    public int getMaximum() { return max; } //*5
    public int getMinimum() { return min; } //*5
    public int getOrientation() { return VERTICAL; } //*5
    public int getUnitIncrement() { return incr; } //*5
    public int getBlockIncrement () { return incr; } //*5
    public int getVisibleAmount() { return 0; } //*5
    public void setBlockIncrement(int b) { incr = b; } //*5
    public void setMaximum(int max) { this.max = max; } //*5
    public void setMinimum(int min) { this.min = min; } //*5
    public void setUnitIncrement(int u) { incr = u; } //*5
    public void setVisibleAmount(int v) { } //*5

    public void setValue(int v) { //*5
	value = v; //*5
	refreshLabel (); //*5
    }
}
[download file]