JList
and JComboBox
are two ways to let the user choose
from a set of values. A JComboBox
has
added flexibility when it is made editable, but, in general, both of these
components are limited in that they can only prompt the user from a fixed
set of choices. In Java 1.4, Swing added a component called JSpinner
that is useful for large or open-ended
sequences of values such as numbers or dates. The JSpinner
is a cousin of the JComboBox
; it displays a value in a field, but
instead of providing a drop-down list of choices, it gives the user a
small pair of up and down arrows for moving over a range of values (see
Figure 17-5). Like the combo box, a
JSpinner
can also be made editable,
allowing the user to type a valid value directly into the field.
Swing provides three basic types of Spinner
s, represented by three different data
models for the JSpinner
component:
SpinnerListModel
,
SpinnerNumberModel
, and
SpinnerDateModel
.
The SpinnerListModel
acts like a
combo box, specifying a fixed set of objects:
String
[]
options
=
new
String
[]
{
"small"
,
"medium"
,
"large"
,
"huge"
};
SpinnerListModel
model
=
new
SpinnerListModel
(
options
);
JSpinner
spinner
=
new
JSpinner
(
model
);
You can retrieve the current value from the model at any time:
String
value
=
(
String
)
model
.
getValue
();
Alternatively, you can register a ChangeListener
to receive updates as the user
changes values. With a SpinnerListModel
, if the spinner is editable and
the user enters a value directly, it is validated against the set of
choices before being accepted. This behavior is a little different from
the other types of SpinnerModel
s which,
when editable, accept any valid value of the correct type (e.g., a number
or date).
The SpinnerNumberModel
displays
numeric values. It can be configured with initial, minimum, and maximum
values:
double
initial
=
5.0
,
min
=
0.0
,
max
=
10.0
,
increment
=
0.1
;
SpinnerNumberModel
model
=
new
SpinnerNumberModel
(
initial
,
min
,
max
,
increment
);
JSpinner
spinner
=
new
JSpinner
(
model
);
Here we have constructed a spinner with an initial value of 5.0 that
allows the user to change the value to between 0 and 10.0 in increments of
0.1. The SpinnerNumberModel getNumber()
method retrieves the current value.
Perhaps the most interesting feature of the JSpinner
is the SpinnerDateModel
, which allows the user to
choose calendar dates by moving in specified increments of time. The
SpinnerDateModel
accepts a range, such
as the SpinnerNumberModel
, but the
values are Date
objects and the
increment is a java.util.Calendar
constant field such as Calendar.DAY
,
Calendar.WEEK
, and so on. The following
example, DateSelector
, creates a
JSpinner
showing the current date and
time. It allows the user to change the date in increments of one week,
over a range of one year (six months forward or back). A ChangeListener
is registered with the model to
display the values as they are modified:
import
java.awt.*
;
import
java.awt.event.*
;
import
javax.swing.*
;
import
javax.swing.event.*
;
import
java.util.*
;
public
class
DateSelector
{
public
static
void
main
(
String
[]
args
)
{
JFrame
frame
=
new
JFrame
(
"DateSelector v1.0"
);
Calendar
now
=
Calendar
.
getInstance
();
Calendar
earliest
=
(
Calendar
)
now
.
clone
();
earliest
.
add
(
Calendar
.
MONTH
,
-
6
);
Calendar
latest
=
(
Calendar
)
now
.
clone
();
latest
.
add
(
Calendar
.
MONTH
,
6
);
SpinnerModel
model
=
new
SpinnerDateModel
(
now
.
getTime
(),
earliest
.
getTime
(),
latest
.
getTime
(),
Calendar
.
WEEK_OF_YEAR
);
final
JSpinner
spinner
=
new
JSpinner
(
model
);
// Disable the built-in date editor
spinner
.
setEditor
(
new
JSpinner
.
DefaultEditor
(
spinner
)
);
model
.
addChangeListener
(
new
ChangeListener
()
{
public
void
stateChanged
(
ChangeEvent
e
)
{
System
.
out
.
println
(
((
SpinnerDateModel
)
e
.
getSource
())
.
getDate
()
);
}
}
);
frame
.
getContentPane
().
add
(
"North"
,
new
JLabel
(
"Choose a week"
)
);
frame
.
getContentPane
().
add
(
"Center"
,
spinner
);
frame
.
pack
();
frame
.
setDefaultCloseOperation
(
JFrame
.
EXIT_ON_CLOSE
);
frame
.
setVisible
(
true
);
}
}
As we said, the SpinnerCalendarModel
acts just like the SpinnerNumberModel
, except that it works with
Date
objects and uses the special
Calendar
constants as increments. To
create dates
, we construct a Calendar
object for the correct time and use its
getTime()
method. In this example, we
used the Calendar
’s add()
method to set the minimum and maximum
values six months in each direction. Table 17-1 shows values for increments in the
Calendar
.
Table 17-1. Calendar field values
Field value | Increment |
---|---|
One millisecond | |
One second | |
One minute | |
| One hour |
A.M. or P.M. | |
One day | |
One month | |
One year | |
B.C. or A.D. in the Gregorian calendar |
The SpinnerDateModel
uses the
Calendar add()
method with a value of
1
or -1
and the corresponding constant value to
increment or decrement the value. Increments of one have the same effect
on several of the constants, as indicated in Table 17-1.
Get Learning Java, 4th Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.