swing组件介绍(2)
19.JProgressBar
进度条.当一个任务要较长时间来完成时,我们可以用一个进度条来表示任务的完成进度.
在讲进度条的用法之前,我们先来看javax.swing.SwingWorker类的用法.我们将用这个类来模拟我们的”较长的任务”.
在java中,组件是在一个用户界面线各里绘制的.如果我们把一个用时较长的任务放到这个线程来实现(例如我们把一个用时较长的任务放到一个按钮的
actionPerformed(…)),那么用户界面将会僵死(例如包含那个按钮的窗口的菜单将暂不可用,而要等actionPerform完成返回后才可用).
通过SwingWorker,我们可以把这个较长的任务放到另外一个线程来实现,这样用户界面就不会僵死了.
这个SwingWorker是jdk1.6才引进的,.之前也有一个SwingWorker.但是它们有所不同:旧的SwingWorker是可重用的,而新的不能;另外它们的方法的名字也不一样.
SwingWorker主要有六个方法doInBackground,get,done,publish,process,execute
SwingWorker是一个泛型类,有两个类型参数.第一类型参数就是doInBackground和get的返回值的类型,而第二个类型参数是publish的形参类型…….
我们的较长任务是在doInBackground里完成的,doInBackground的返回值可以用get取得.get有无参和无参两个版本,参数代表的是等待doInBackground完成的时间,无参表示直到doInBackground完成,get才返回.
get要等到doInBackground完成才知道任务完成情况.怎么了解任务的执行过程呢?publish可以做到这一点.publish的参数个数是任意的,但是,每一个参数的类型都必须是SwingWorker的第二个类型参数指定的类型.
我们用publish向外界发布任务执行的情况,而用process来收集这些情况.process是在事件分发线程中执行的.在它被执行之前,SwingWorker的publish可能已经执行多次,所以process的参数是一个List,这样就可以包含所有publish了的情况.
done是在doInBackground执行完成之后执行的.
execute是使doInBackground开始执行.
以上的方法只有doInBackground是必须自己实现的,其他都是可选的.
下面是一个例子.在这个例子中有两个按钮.第一个按钮使SwingWorker开始工作,第二个按钮调用get方法取得doInBackground的返回值.
在SwingWorker开始工作以后但是还没有结束前按下第二个按钮,可以看到界面僵死了,这是因为我们在按钮的actionPerformed(在事件分发线程里调用)里调用了get,而无参的get在doInBackground返回前是不会返回的.
在doInBackground完成之后,我们再按下第一个按钮,程序并没有变化.这是因为SwingWorker是不可重用的.所以我们用匿名内部类来实现我们的SwingWorker.
在程序中我们还用到了publish和process.在process中,我们输出publish的结果.按下第二个按钮之前,process 每次只输出一个值,而在doInBackground返回之前按下第二个按钮,因为process是在事件分发线程里执行的,而get阻塞了事件分发线程,所以process不再输出了,而是等到最后连续输出数个值.
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.util.concurrent.ExecutionException;
class SwingWorkerTest
{
JFrame mainFrame;
JPanel mainPanel;
JButton button;
JButton getButton;
public SwingWorkerTest() {
mainFrame = new JFrame ( );
mainPanel = new JPanel ();
final javax.swing.SwingWorker<Integer,Integer> worker =
new javax.swing.SwingWorker<Integer,Integer>(){
public Integer doInBackground(){
int coutn = 0;
while( (coutn++)<10 ){
try{
System.out.println( “doInBackground() is doing a long job” );
Thread.sleep(1000);
publish( new Integer( (int)(Math.random()*1000) ) );
}catch( InterruptedException e ){
e.printStackTrace();
}
}
return new Integer(3);
}
@Override
public void process(List<Integer> integers){
int i = 0;
Iterator iterator = integers.iterator();
while( iterator.hasNext() ){
i++;
Integer integer = (Integer)iterator.next();
System.out.println( “在process输出publish的值”+i+” “+integer );
}
}
};
button = new JButton (“start”);
button.addActionListener( new ActionListener(){
public void actionPerformed( ActionEvent e){
worker.execute();
}
});
getButton = new JButton (“Get”);
getButton.addActionListener( new ActionListener(){
public void actionPerformed( ActionEvent e){
try{
System.out.println( “doInBackground的返回值: “+worker.get() );
}catch( InterruptedException ie ){
ie.printStackTrace();
}catch( ExecutionException ee ){
ee.printStackTrace();
}
}
});
mainPanel.add(button);
mainPanel.add(getButton);
mainFrame.getContentPane().add( mainPanel );
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible( true );
}
public static void main(String[] args)
{
new SwingWorkerTest();
}
}
除了用JProgressBar来显示进度,我们还可以用ProgressMonitor来实现.
ProgressMonitor提供了创建进度条的简便方法,它显示的进度条出现在一个对话框里
它只有一个构造方法:ProgressMonitor(Component parentComponent, Object message, String note, int min, int max)
message和note参数都是和进度条一起显示在对话框里,不同的是,note是可变的,而message不可以.min和max是进度的最小值和最大值
这个对话框并不是在任务一开始就显示出来的,而是等500个百万分之一秒再出来,这个”500″可以用void setMillisToPopup(int millisToPopup)来设定,参数的单位是百万分之一秒;而且,如果它计算得知这个任务用时不超过2000个百万分之一秒,那么这个对话框就永远不会出来.这个”2000″,可以用void setMillisToDecideToPopup(int)来设定,参数的单位也是百万分之一秒
它其他的方法有:
int getMillisToPopup()
void setMinimum(int m),void setMaximum(int m),void setNote(String note),void setProgress(int nv)
int getMinimum() , int getMaximum() ,String getNote() ,没有int getProgress()
boolean isCanceled()
这里再介绍SwingWorker的几个方法:
setProgress:设置任务的进度
getProgress:得到任务的进度
可以用addPropertyChangeListener(PropertyChangeLitener)对上面两个方法的调用作出响应
cancel(boolean):取消任务
isCancelled():判断任务是否已被取消
下面是一个例子.
package blog.swing;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.Random;
import java.beans.*;
class ProgressMonitorDemo
{
JFrame mainFrame;
ProgressMonitor simpleProgressMonitor;
JButton startButton;
Worker worker;
public ProgressMonitorDemo() {
mainFrame = new JFrame ( “ProgressMonitorDemo” );
startButton = new JButton (“Start”);
startButton.addActionListener( new ActionListener(){
public void actionPerformed( ActionEvent e){
simpleProgressMonitor = new ProgressMonitor(mainFrame,”正在执行任务”,”",0,100);
simpleProgressMonitor.setMillisToDecideToPopup(0);
simpleProgressMonitor.setMillisToPopup(0);
worker = new Worker();
worker.addPropertyChangeListener( new PropertyChangeListener(){
public void propertyChange( PropertyChangeEvent e ){
if( “progress”.equals( e.getPropertyName() )){
int progress = (Integer)e.getNewValue();
simpleProgressMonitor.setProgress( progress );
String message = String.format(“%d%% completed”,progress);
simpleProgressMonitor.setNote(message);
}
}
});
worker.execute();
startButton.setEnabled(false);
}
} );
mainFrame.getContentPane().add( startButton,BorderLayout.LINE_START );
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible( true );
}
public static void main(String[] args)
{
new ProgressMonitorDemo();
}
class Worker extends javax.swing.SwingWorker<Void,Void>{
public Void doInBackground(){
int progress = 0;
Random r = new Random();
while( progress<=100 && !isCancelled() ){
progress += r.nextInt(10);
setProgress( Math.min(progress,100) );
try{
Thread.sleep( r.nextInt(1000) );
}catch( InterruptedException e ){
e.printStackTrace();
}
}
return null;
}
public void done(){
startButton.setEnabled(true);
}
}
}
20.JTabbedPane
选项卡.
构造方法:JTabbedPane() ,JTabbedPane(int tabPlacement) ,JTabbedPane(int tabPlacement, int tabLayoutPolicy)
添加选项卡:
void addTab(String title, Component component)
void addTab(String title, Icon icon, Component component)
void addTab(String title, Icon icon, Component component, String tip)
void insertTab(String title, Icon icon, Component component, String tip, int index)
删除选项卡:
void remove(int index)
void removeAll()
void removeTabAt(int index)
修改选项卡上显示的组件:
void setComponentAt(int index, Component component)
Component getComponentAt(int index)
设置外观:
void setTabPlacement(int tabPlacement):JTabbedPane.TOP, JTabbedPane.BOTTOM ,JTabbedPane.LEFT,JTabbedPane.RIGHT
void setTabLayoutPolicy(int tabLayoutPolicy) :JTabbedPane.WRAP_TAB_LAYOUT ,JTabbedPane.SCROLL_TAB_LAYOUT
void setTitleAt(int index, String title)
void setToolTipTextAt(int index, String toolTipText)
void setIconAt(int index, Icon icon)
void setBackgroundAt(int index, Color background)
void setForegroundAt(int index, Color foreground)
查找选项卡:
int indexAtLocation(int x, int y)
int indexOfComponent(Component component)
int indexOfTab(Icon icon)
int indexOfTab(String title)
和选择有关的:
int getSelectedIndex()
void setSelectedIndex(int index)
Component getSelectedComponent()
void setSelectedComponent(Component c)
自定义标签上的组件:
void setTabComponentAt(int index, Component c);
Component getTabComponentAt(int index);
package blog.swing;
import javax.swing.*;
import java.awt.Color;
class JTabbedPaneDemo
{
JFrame mainFrame;
JTabbedPane simpleTabbedPane;
public JTabbedPaneDemo() {
mainFrame = new JFrame ( “JTabbedPaneDemo” );
simpleTabbedPane = new JTabbedPane();
simpleTabbedPane.setTabLayoutPolicy( JTabbedPane.SCROLL_TAB_LAYOUT );
simpleTabbedPane.addTab(“Tab1″,new JLabel (“Component1″));
simpleTabbedPane.addTab(“Tab2″,new JLabel (“Component2″));
simpleTabbedPane.addTab(“Tab3″,new JLabel (“Component3″));
simpleTabbedPane.addTab(“Tab4″,new JLabel (“Component4″));
for(int i=0; i<4; i++){
simpleTabbedPane.setTabComponentAt( i,new JButton (“”+i));
simpleTabbedPane.setBackgroundAt(i,Color.white);
}
mainFrame.getContentPane().add( simpleTabbedPane );
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible( true );
}
public static void main(String[] args)
{
new JTabbedPaneDemo();
}
}
21.JFormattedTextField
在讲JFormattedTextField之前,先讲用于指定格式的类:
Locale,NumberFormat,DecimalFormat,DecimalFormatSymbols,DateFormat,SimpleDateFormat,DateFormatSymbols
根据地区/语言(Locale)的不同,各种数字,日期的格式会有所不同.例如902333这个数字在德国会写作902.333,而在美国写作902,333
创建Locale可以使用它的构造方法,也可以使用它的一些常量.例如下面两个语句是等价的:
Locale locale1 = new Locale(“zh”,”CN”);
Locale locale2 = Locale.CHINA;
上面用到的”zh”(小写)和”CN”(大写)分别遵循着一定的规定,在下面的链接可以找到这些搭配:
http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
你可以用任意的”xx”和”XX”搭配来创建Locale,但是,并不是所有都是有意义的,即Locale不一定可被上面的XXXFormat使用.
使用下面的程序可以得到DateFormat可以使用的组合:
package blog.swing;
import java.util.Locale;
import java.text.DateFormat;
class AvailableLocale
{
public static void main(String[] args)
{
Locale[] locales = DateFormat.getAvailableLocales();
for( Locale locale : locales ){
System.out.println( locale.toString());
//System.out.println( locale.getDisplayName() );
}
}
}
如果你不设定Locale,XXXFormat将使用默认的Locale.这个默认的Locale是和你所用的系统有关的
用Locale.getDefault()可以得到默认的Locale
NumberFormat可以用于数字,货币和百分数的格式化(根据不同的Locale).对于数字,货币和百分数,分别调用静态方法getNumberInstanc(Locale),
getCurrencyInstance(Locale),getPercentInstance(Locale)来取得实例,再用String format(double)来返回格式化后的字符串.
DecimalFormat是NumberFormat的子类,它对格式提供了更多的控制.在构造它的时候可以指定数字显示格式.它不可以直接指定Locale.要指定Locale的时候,可以把一个NumberFormat强制转换为DecimalFormat,再调用 applyPattern(String pattern)来指定数字格式.
同样它用String format(double)来返回格式化后的字符串.
可以用DecimalFormatSymbols来指定数字里面的各个符号,例如小数点.在DecimalFormat的构造方法里传入 DecimalFormatSymbols就可以了.DecimalFormatSymbols还可以指定Locale,所以用了 DecimalFormatSymbols就不用将一个NumberFormat转换为Decimalformat以指定Locale了
package blog.swing;
import java.util.Locale;
import java.text.NumberFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
class NumberFormatDemo{
public static void main( String[] args ){
double number = 96356.127;
double currency = 56832.523;
double percent = 0.72;
String out;
Locale locales[] = { Locale.CHINA,Locale.US,Locale.GERMANY };
NumberFormat formats = NumberFormat.getNumberInstance();
for( int i=0; i<3; i++){
formats = NumberFormat.getNumberInstance( locales[i] );
out = formats.format( number );
System.out.println( out+” “+locales[i].getDisplayName() );
formats = NumberFormat.getCurrencyInstance( locales[i] );
out = formats.format( currency );
System.out.println( out+” “+locales[i].getDisplayName() );
formats = NumberFormat.getPercentInstance( locales[i] );
out = formats.format( percent );
System.out.println( out+” “+locales[i].getDisplayName() );
}
DecimalFormat df = new DecimalFormat();
String pattern = “@#,###.##”;
df.applyPattern( pattern );
out = df.format(number);
System.out.println( out );
pattern = “#@###.####”;
df.applyPattern( pattern );
out = df.format(number);
System.out.println( out );
df = (DecimalFormat)formats;
df.applyPattern(“#,###.##”);
out = df.format(number);
System.out.println( out );
DecimalFormatSymbols dfss = new DecimalFormatSymbols(Locale.GERMANY);
dfss.setDecimalSeparator(‘^’);
df.setDecimalFormatSymbols( dfss );
df.applyPattern(“00,000.000″);
out = df.format(number);
System.out.println( out );
}
}
pattern的格式应满足:
pattern := subpattern{;subpattern}
subpattern := {prefix}integer{.fraction}{suffix}
prefix := ‘\\’..’\\?’ – specialCharacters
suffix := ‘\\’..’\\?’ – specialCharacters
integer := ‘#’* ’0′* ’0′
fraction := ’0′* ‘#’*
上面讲的都是和数字有关的,下面讲的是和日期和时间有关的
和日期,时间有关的格式用DateFormat,它的用法和NumberFormat差不多,也是调用静态方法来取得实例,再调用String format(Date)来返回格式化后的字符串
这些静态方法有:
DateFormat getDateInstance(),DateFormat getDateInstance(int style),DateFormat getDateInstance(int style, Locale aLocale)
DateFormat getTimeInstance(),DateFormat getTimeInstance(int style),DateFormat getTimeInstance(int style, Locale aLocale)
DateFormat getDateTimeInstance(),DateFormat getDateTimeInstance(int style),DateFormat getDateTimeInstance(int style, Locale aLocale)
第一个参数指定显示的风格,根据第二个参数的不同,这些风格也有所不同.可以取的值有:
DEFAULT,LONG,MEDIUM,SHORT,FULL,它们都是DateFormat的静态常量.
对应于数字的DecimalFormat,在日期时间方面,有一个SimpleDateFormat
与DecimalFormat不同的是,SimpleDateFormat在构造的时个就可指定Locale了.
与数字的DeciamlFormatSymblos对应,在日期时间方面,有一个DateFormatSymbols.
package blog.swing;
import java.util.Locale;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.DateFormatSymbols;
class DateTimeFormatDemo
{
public static void main(String[] args)
{
Calendar calendar = new GregorianCalendar();
Date date = calendar.getTime();
Locale[] locales = { Locale.CHINA,Locale.US,Locale.GERMANY };
String[] patterns = { “yy-MM-dd”,”E yyyy/MM/dd”,”yy.MM.dd.hh.mm.ss” };
DateFormat formats;
SimpleDateFormat sdf;
String out;
for( int i=0; i<3; i++ ){
formats = DateFormat.getDateInstance(DateFormat.DEFAULT,locales[i]);
out = formats.format( date );
System.out.println( out );
formats = DateFormat.getTimeInstance(DateFormat.LONG,locales[i]);
out = formats.format( date );
System.out.println( out );
formats = DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL,locales[i]);
out = formats.format( date );
System.out.println( out );
sdf = new SimpleDateFormat(patterns[i],locales[i]);
out = sdf.format( date );
System.out.println( out+” “+patterns[i] );
System.out.println( “=====================” );
}
DateFormatSymbols dfss = new DateFormatSymbols(Locale.CHINA);
sdf = new SimpleDateFormat();
String[] capitalDays = {
“”,”SUN-星期日”, “MON-星期一”, “TUE-星期二”, “WED-星期三”,
“THU-星期四”, “FRI-星期五”, “SAT-星期六”};
dfss.setShortWeekdays(capitalDays);
sdf.applyPattern(“E”);
sdf.setDateFormatSymbols( dfss );
out = sdf.format(date);
System.out.println( out );
}
}
下面是一个JFormattedTextField的例子.在这个例子中的三个JFormattedTextField分别使用了 NumberFormat的三个静态方法取得的NumberFormat,当它们失去焦点时,它们显示的文本就会被格式化再重新显示,如果输入的是无效的文本,则文本被重设为上次的有效文本.
package blog.swing;
import java.awt.GridLayout;
import java.awt.Container;
import javax.swing.BorderFactory;
import javax.swing.*;
import java.text.NumberFormat;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
class JFormattedTextFieldDemo implements PropertyChangeListener
{
JFrame mainFrame;
JPanel mainPanel;
JFormattedTextField priceFormattedTextField;
JFormattedTextField discountFormattedTextField;
JFormattedTextField paymentFormattedTextField;
JLabel priceLabel;
JLabel discountLabel;
JLabel paymentLabel;
NumberFormat priceFormat;
NumberFormat discountFormat;
NumberFormat paymentFormat;
public JFormattedTextFieldDemo() {
mainFrame = new JFrame ( “JFormattedTextFieldDemo” );
mainPanel = new JPanel ( new GridLayout(3,2) );
mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
priceFormat = NumberFormat.getNumberInstance();
priceFormattedTextField = new JFormattedTextField(priceFormat);
priceFormattedTextField.setValue(72.023);
priceFormattedTextField.addPropertyChangeListener(“value”,this);
priceLabel = new JLabel (“Price”);
priceLabel.setLabelFor( priceFormattedTextField );
mainPanel.add( priceLabel );
mainPanel.add( priceFormattedTextField );
discountFormat = NumberFormat.getPercentInstance();
discountFormattedTextField = new JFormattedTextField(discountFormat);
discountFormattedTextField.setValue(0.75);
discountFormattedTextField.addPropertyChangeListener(“value”,this);
discountLabel = new JLabel (“Discount”);
discountLabel.setLabelFor( discountFormattedTextField );
mainPanel.add( discountLabel );
mainPanel.add( discountFormattedTextField );
paymentFormat = NumberFormat.getCurrencyInstance();
paymentFormattedTextField = new JFormattedTextField(paymentFormat);
paymentFormattedTextField.setEditable( false );
paymentFormattedTextField.addPropertyChangeListener(“value”,this);
paymentLabel = new JLabel (“Payment”);
paymentLabel.setLabelFor( paymentFormattedTextField );
mainPanel.add( paymentLabel );
mainPanel.add( paymentFormattedTextField );
mainFrame.getContentPane().add( mainPanel );
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible( true );
}
public void propertyChange( PropertyChangeEvent e ){
double price = ((Number)priceFormattedTextField.getValue()).doubleValue();
double discount = ((Number)discountFormattedTextField.getValue()).doubleValue();
paymentFormattedTextField.setValue( price*discount );
}
public static void main(String[] args)
{
new JFormattedTextFieldDemo();
}
}
除了使用上面讲到的java.text包中的各种formatter,还可以使用javax.swing.text.MaskFormatter来限制用户可以输入的字符
package blog.swing;
import javax.swing.*;
import javax.swing.text.MaskFormatter;
import java.text.ParseException;
class MaskFormatterDemo
{
JFrame mainFrame;
JFormattedTextField simpleFormattedTextField;
MaskFormatter mask;
public MaskFormatterDemo(){
mainFrame = new JFrame ( “MaskFormatterDemo” );
try{
mask = new MaskFormatter(“####”);
simpleFormattedTextField = new JFormattedTextField( mask );
mainFrame.getContentPane().add( simpleFormattedTextField );
}catch( ParseException e ){
e.printStackTrace();
}
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible( true );
}
public static void main(String[] args)
{
new MaskFormatterDemo();
}
}
22.JSpinner
微调组件.
微调组件由Editor,微调按钮,和它的Model组成.
在构造JSpinner时,可以指定它的Model.
swing提供了三个Model:
SpinnerListModel,SpinnerNumberModel,SpinnerDateModel
结构是SpinnerModel
|_AbstractSpinnerModel
|_SpinnerListModel,SpinnerNumberModel,SpinnerDateModel
对应有三个Editor:
JSpinner.ListEditor,JSpinner.NumberEditor,JSpinner.DateEditor,三个都是JSpinner.DefaultEditor的子类
JSpinner.DefaultEditor
|_JSpinner.ListEditor,JSpinner.NumberEditor,JSpinner.DateEditor
可以看到,有很大的空间可以自定义一个JSpinner
当你需要自定义它的Editor时,你可以用void setEditor(JComponent editor),也可以用JSpinner.DefaultEditor.getTextField()来取得JFormattedTextField, 然后对这个JFormattedTextField来调用方法.
可以通过addChangeListener对JSpinner值的改变作出反应.
package blog.swing;
import java.awt.GridLayout;
import java.awt.Color;
import javax.swing.*;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.util.Date;
import java.util.Calendar;
import java.text.DecimalFormat;
class JSpinnerDemo implements ChangeListener
{
JFrame mainFrame;
JPanel mainPanel;
JSpinner listSpinner;
JSpinner numberSpinner;
JSpinner dateSpinner;
public JSpinnerDemo() {
mainFrame = new JFrame ( “JSpinnerDemo” );
mainPanel = new JPanel ( new GridLayout(3,1) );
String[] listData = { “SpinnerListModel”,”SpinnerNumberModel”,”SpinnerDateModel” };
//使用自定义的Model来实现cycle
SpinnerModel listModel = new CustomSpinnerListModel(listData);
listSpinner = new JSpinner( listModel );
listSpinner.addChangeListener( this );
mainPanel.add(listSpinner);
SpinnerModel numberModel = new SpinnerNumberModel(1.0,0.0,2.0,0.1);
numberSpinner = new JSpinner( numberModel );
numberSpinner.addChangeListener( this );
//通过取得JFormattedTextField来自定义Editor
JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor)numberSpinner.getEditor();
JFormattedTextField ftf = editor.getTextField();
ftf.setForeground( Color.red );
mainPanel.add( numberSpinner );
Calendar calendar = Calendar.getInstance();
Date initDate = calendar.getTime();
calendar.add(Calendar.YEAR,-100);
Date earliestDate = calendar.getTime();
calendar.add(Calendar.YEAR,200);
Date latestDate = calendar.getTime();
SpinnerModel dateModel = new SpinnerDateModel(initDate,earliestDate,latestDate,Calendar.YEAR);
dateSpinner = new JSpinner( dateModel );
dateSpinner.addChangeListener( this );
//通过setEditor来自定义Editor
dateSpinner.setEditor( new JSpinner.DateEditor(dateSpinner,”yyyy-MM-dd”) );
mainPanel.add(dateSpinner);
mainPanel.setBorder( BorderFactory.createEmptyBorder(10,10,10,10) );
mainFrame.getContentPane().add( mainPanel );
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible( true );
}
public void stateChanged( ChangeEvent e ){
JSpinner spinner = (JSpinner)e.getSource();
System.out.println( spinner.getValue() );
}
//自定义的Model,实现Cycle.
class CustomSpinnerListModel extends SpinnerListModel{
Object[] values;
CustomSpinnerListModel( Object[] values ){
super(values);
this.values = values;
}
public Object getPreviousValue(){
Object value = super.getPreviousValue();
return value != null ? value : values[values.length-1];
}
public Object getNextValue(){
Object value = super.getNextValue();
return value != null ? value : values[0];
}
}
public static void main(String[] args)
{
new JSpinnerDemo();
}
}