到目前为止,我们已经了解了如何与主JSpinner类交互。SpinnerModel接口是组件的数据模型。SpinnerModel的定义如下:
public interface SpinnerModel { // Properties public Object getValue(); public void setValue(Object); public Object getNextValue(); public Object getPreviousValue(); // Listeners public void addChangeListener(ChangeListener); public void removeChangeListener(ChangeListener); }
SpinnerMOdel的六个方法直接映射到JSpinner的相应方法。JSpinner方法只是将这些方法调用转向模型的方法,尽管在监听器方法的情况下,事件源是我们关联监听器的地方。
SpinnerModel接口的基本实现是AbstractSpinnerModel类。他提供了监听器列表的管理与通知。子类必须实现其他的四个与值相关的接口方法。SpinnerModel接口的实现有:SpinnerDateModel,SpinnerListModel与SpinnerNumberModel。
正如其名字所暗示的,SpinnerModel提供了日期的选择。这个类有两个构造函数:一个在默认情况下选择所有的日期,而另一个允许我们限制范围。
public SpinnerDateModel() SpinnerModel model = new SpinnerDateModel(); JSpinner spinner = new JSpinner(model); public SpinnerDateModel(Date value, Comparable start, Comparable end, int calendarField) Calendar cal = Calendar.getInstance(); Date now = cal.getTime(); cal.add(Calendar.YEAR, -50); Date startDate = cal.getTime(); cal.add(Calendar.YEAR, 100); Date endDate = cal.getTime(); SpinnerModel model = new SpinnerDateModel(now, startDate, endDate, Calendar.YEAR); JSpinner spinner = new JSpinner(model);
如果我们没有指定任何参数,则没有起始点与结束点。这里所显示的示例使用参数来提供100年的范围。最后一个域应是Calendar类的一个常量:
•Calendar.AM_PM
•Calendar.DAY_OF_MONTH
•Calendar.DAY_OF_WEEK
•Calendar.DAY_OF_WEEK_IN_MONTH
•Calendar.DAY_OF_YEAR
•Calendar.ERA
•Calendar.HOUR
•Calendar.HOUR_OF_DAY
•Calendar.MILLISECOND
•Calendar.MINUTE
•Calendar.MONTH
•Calendar.SECOND
•Calendar.WEEK_OF_MONTH
•Calendar.WEEK_OF_YEAR
• Calendar.YEAR
注意,SpinnerModel不包含任何与时区相关的Calendar常量。我们不可以通过SpinnerDateModel在JSpinner内进行滚动。
表14-3列出了SpinnerModel接口的三个属性以四个SpinnerDateModel的特定属性。
通常情况下,我们将会使用的唯一新属性是用于获取最终的日期,尽管他所做的是以合适的数据类型包装getValue()的方法的结果。如果我们为构造函数提供了一个日期范围,在当前值为边界条件时,前一个或是后一个值将为null。
SpinnerListModel提供了由条目列表中,或者是至少是他们的字符串表示中进行选择。这个类有三个构造函数:
public SpinnerListModel() SpinnerModel model = new SpinnerListModel(); JSpinner spinner = new JSpinner(model); public SpinnerListModel(List<?> values) List<String> list = args; SpinnerModel model = new SpinnerListModel(list); JSpinner spinner = new JSpinner(model); public SpinnerListModel(Object[] values) SpinnerModel model = new SpinnerListModel(args); JSpinner spinner = new JSpinner(model);
当没有提供参数时,模型只包含一个元素:字符串empty。List版本具有一个到列表的引用。他并没有拷贝这个列表。如果我们修改这个列表,我们就修改了模型中的元素。数组版本创建了一个不可以添加的私有的List实例的内联类。对于List与数组版本,初始时选中的是第一个元素。如果其中一个为空,则会抛出IllegalArgumentException。
如表14-4所示,在接口之外所添加的唯一属性就是获取或是设置列表。
SpinnerNumberModel提供了由一个无限制或是有限制的值范围内进行数字选择。所选择的数字可以是Number的任意子类,包括Integer与Double。这个类具有四个构造函数,而前三个都是最后一个的简化版。
public SpinnerNumberModel() SpinnerModel model = new SpinnerNumberModel(); JSpinner spinner = new JSpinner(model); public SpinnerNumberModel(double value, double minimum, double maximum, double stepSize) SpinnerModel model = new SpinnerNumberModel(50, 0, 100, .25); JSpinner spinner = new JSpinner(model); public SpinnerNumberModel(int value, int minimum, int maximum, int stepSize) SpinnerModel model = new SpinnerNumberModel(50, 0, 100, 1); JSpinner spinner = new JSpinner(model); public SpinnerNumberModel(Number value, Comparable minimum, Comparable maximum, Number stepSize) Number value = new Integer(50); Number min = new Integer(0); Number max = new Integer(100); Number step = new Integer(1); SpinnerModel model = new SpinnerNumberModel(value, min, max, step); JSpinner spinner = new JSpinner(model);
如果最小值或是最大值为null,则这个范围就是无限制的。对于无参数的版本,初始值为0而步进值为1。步进尺寸是字面值,所以如果我们将这个步进值设置为.333,则并不完美。
表14-5显示了SpinnerNumberModel的属性。所添加的属性与构造函数所提供的相同。
通常情况下,JSpinner的可用模型就足够了,所以我们并不需要派生。然而,所提供的模型并不能总是满足我们的需求。例如,我们也许希望使用一个包装了SpinnerListModel的自定义模型,而不希望停在第一个或是最后一个元素上,他向另一个方向环绕。列表14-2显示了一个这样的实现。
package swingstudy.ch13; import java.util.List; import javax.swing.SpinnerListModel; public class RolloverSpinnerListModel extends SpinnerListModel { public RolloverSpinnerListModel(List<?> values) { super(values); } public RolloverSpinnerListModel(Object[] values) { super(values); } public Object getNextValue() { Object returnValue = super.getNextValue(); if(returnValue == null) { returnValue = getList().get(0); } return returnValue; } public Object getPreviousValue() { Object returnValue = super.getPreviousValue(); if(returnValue == null) { List list = getList(); returnValue = list.get(list.size()-1); } return returnValue; } }