Magic with Merlin: Swing's new Spinner component

Allow users to quickly choose dates, numbers, and selections from pick lists with JSpinner

Welcome to Magic with Merlin, a bi-weekly series designed to give you a leg up on programming with Java 2 Standard Edition, version 1.4. Over the coming months, author John Zukowski will offer tips and tricks for navigating the wealth of new features in this release. In this installment, John describes the new JSpinner component of Swing, which allows you to choose dates, numbers, and selections from pick lists.

Share:

John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc.

Author photoJohn Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and serves as the resident guru for a number of jGuru's community-driven Java FAQs. His latest books are Java Collections and Definitive Guide to Swing for Java 2 (2nd ed) from Apress. Contact John at jaz@zukowski.net.



01 July 2001

Also available in Japanese

The most recent release of the Java 2 SDK, the 1.4 beta, adds two powerful new components to the JFC/Swing component set. One of them, JSpinner, allows a user to easily select a date, number, or choice from a pick list. (The other is JFormattedTextField for formatted input support.)

Getting started

JSpinner lets you create an ordered list of values, which it displays one at a time in a selection box, as shown in Figure 1. Users click the up and down arrows to make selections.

Figure 1. Sample JSpinner
Sample JSpinner

Users make a selection by using the up and down arrows on the component or on the keyboard. They can also type in their choice. Unlike a JComboBox, however, JSpinner does not provide a drop-down list of selections so the choices and their order should make sense.

To use the class, simply create a collection of elements to choose from (in either a List or array), create a SpinnerModel from the list, and create a JSpinner for the model:

Listing 1. Simple JSpinner Usage
  String[] months = new DateFormatSymbols().getMonths();
  SpinnerModel model = new SpinnerListModel(months);
  JSpinner spinner = new JSpinner(model);

There are several helper classes for creating the data model for the component, depending on the type of input you're after:

  • SpinnerDateModel: Used for accepting date input. This class supports changing the date by different settings via constants in the Calendar class; for example, Calendar.WEEK_OF_MONTH to change the date one week at a time.
  • SpinnerListModel: Used for accepting input from a list of values.
  • SpinnerNumberModel: Used for accepting input from a range of numbers (int or double) with a set step size.

Each of the SpinnerModel implementations relies on an editor for the input of the value. The editor must be a JComponent; the system-defined editors subclass JSpinner.DefaultEditor. One is available for each of the models:

  • JSpinner.DateEditor: For the SpinnerDateModel. Allows you to customize the input date format.
  • JSpinner.ListEditor: For the SpinnerListModel. Supports type-ahead to locate a value.
  • JSpinner.NumberEditor: For the SpinnerNumberModel. Allows you to customize the decimal format pattern.

The relationships between all these classes (and a few more) are shown in Figure 2.

Figure 2. JSpinner UML relationship diagram
JSpinner UML relationship diagram

Event handling

The JSpinner component works like the other Swing components. If you're interested in finding out when the user changes the selection, you attach a listener. In the case of the JSpinner, that listener is a ChangeListener, which you can attach directly to the JSpinner or its SpinnerModel. While you can attach the listener to either, the source of the ChangeEvent when the value change happens is always the SpinnerModel:

Listing 2. JSpinner event listening
  ChangeListener listener = new ChangeListener() {
    public void stateChanged(ChangeEvent e) {
      SpinnerModel source = (SpinnerModel)e.getSource();
      System.out.println("The value is: " + source.getValue());
    }
  };
  model.addChangeListener(listener);

A complete example

Let's take a look at an example that uses all three of the different spinner models (Listing 3). The list model uses the set of month names, taken from the DateFormatSymbols class. The date model example changes the input format for the editor. (There seems to be a bug in the beta release that doesn't reformat the field when the editor changes.) It also moves the date a week at a time when using the arrows next to the field. The number model example lets the user pick a number from 0 to 100, jumping five at a time when using the arrows. Notice that the user can type in any number, not just those that are multiples of five.

For all the components, the same change listener is attached to display when each spinner value actually changes. If you use the cursor keys to change the month, day, or year, you'll notice the value doesn't change until you hit the Enter key.

Listing 3. JSpinner complete example
import javax.swing.*;
import javax.swing.event.*;
import java.text.*;
import java.awt.*;
import java.util.*;

public class Spinner {
  public static void main (String args[]) throws Exception {
    JFrame frame = new JFrame("Spinner");
    frame.setDefaultCloseOperation(3);
    String[] months = new DateFormatSymbols().getMonths();
    SpinnerModel model = new SpinnerListModel(months);
    JSpinner spinner = new JSpinner(model);
    frame.getContentPane().add(spinner, BorderLayout.NORTH);

    SpinnerDateModel model2 = new SpinnerDateModel();
    model2.setCalendarField(Calendar.WEEK_OF_MONTH);
    JSpinner spinner2 = new JSpinner(model2);
    JSpinner.DateEditor editor2 = new JSpinner.DateEditor(
      spinner2, "MMMMM dd, yyyy");
    spinner2.setEditor(editor2);
    frame.getContentPane().add(spinner2, BorderLayout.SOUTH);

    SpinnerNumberModel model3 = new SpinnerNumberModel(50, 0, 100, 5);
    JSpinner spinner3 = new JSpinner(model3);
    frame.getContentPane().add(spinner3, BorderLayout.CENTER);

    ChangeListener listener = new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        SpinnerModel source = (SpinnerModel)e.getSource();
        System.out.println("The value is: " + source.getValue());
      }
    };
    model.addChangeListener(listener);
    model2.addChangeListener(listener);
    model3.addChangeListener(listener);

    frame.pack();
    frame.show();
  }
}

Download

DescriptionNameSize
Sample codespinner.zip1 KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10560
ArticleTitle=Magic with Merlin: Swing's new Spinner component
publish-date=07012001