Java 即使开始和结束是同一年,JSpinner.DateEditor也必须包含年份
我有一个使用SpinnerDateModel的JSpinner,它从2010年1月1日00:00:00.000开始,结束日期是2010年1月1日00:12:34.217。我希望我的JSpinner.DateEditor使用HH:mm:ss.SSS格式,但微调器不使用此格式旋转。仅当“yyyy”添加到格式时,它才会旋转。我怎样才能避开这件事Java 即使开始和结束是同一年,JSpinner.DateEditor也必须包含年份,java,swing,jspinner,Java,Swing,Jspinner,我有一个使用SpinnerDateModel的JSpinner,它从2010年1月1日00:00:00.000开始,结束日期是2010年1月1日00:12:34.217。我希望我的JSpinner.DateEditor使用HH:mm:ss.SSS格式,但微调器不使用此格式旋转。仅当“yyyy”添加到格式时,它才会旋转。我怎样才能避开这件事 import java.awt.GridLayout; import java.util.*; import javax.swing.*; public c
import java.awt.GridLayout;
import java.util.*;
import javax.swing.*;
public class T extends JPanel {
public T() {
super(new GridLayout(2, 2));
init();
}
private void init() {
Calendar start = GregorianCalendar.getInstance();
Calendar end = GregorianCalendar.getInstance();
start.clear();
end.clear();
start.set(Calendar.YEAR, 2010);
end.set(Calendar.YEAR, 2010);
end.add(Calendar.HOUR_OF_DAY, 12);
SpinnerDateModel m1 =
new SpinnerDateModel(start.getTime(), start.getTime(),
end.getTime(), Calendar.MILLISECOND);
SpinnerDateModel m2 =
new SpinnerDateModel(start.getTime(), start.getTime(),
end.getTime(), Calendar.MILLISECOND);
JSpinner workingSpinner = new JSpinner(m1);
workingSpinner.setEditor(
new JSpinner.DateEditor(workingSpinner,
"yyyy HH:mm:ss.SSS"));
JSpinner notWorkingSpinner = new JSpinner(m2);
notWorkingSpinner.setEditor(
new JSpinner.DateEditor(notWorkingSpinner,
"HH:mm:ss.SSS"));
add(new JLabel("Working"));
add(workingSpinner);
add(new JLabel("!Working"));
add(notWorkingSpinner);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new T());
frame.pack();
frame.setVisible(true);
}
}
我不知道为什么这不起作用,但如果您将m2的声明更改为: SpinnerDateModel m2=新SpinnerDateModel(); m2.setValue(start.getTime())
它是有效的。在对JRE源代码进行了大量的挖掘之后,我发现微调器是由文本值而不是真实日期支持的。点击“向上旋转”和“向下旋转”按钮时,将解析该值,然后将其与最小值和最大值进行比较。因为您的格式没有年份,所以解析日期时,年份始终为1970年,即从历元偏移0的年份。这会导致旋转器在尝试旋转时总是返回超出范围的错误 最快的解决方案是简单地使用1970年而不是2010年。但是,如果您的初始日期是1970年底,微调器不会让您的用户滚动到1971年1月(相反,它可能会跳回到1970年初) 另一种解决方案可以容纳跨越日历年边界的日期。然而,它并没有那么简单(或漂亮)。在JRE中,当DateFormatter解析日期字符串时,它使用单个字符串参数构造函数动态实例化一个类。此字符串是来自微调器的日期。默认情况下,这个类是Date或它的某个子类。我们可以让格式化程序实例化我们自己的Date类,它在执行任何日期比较之前修复年份
添加年份的日期类:
public static class DateThatAddsYear extends Date {
public DateThatAddsYear( String time ) {
super( time );
Calendar cal = GregorianCalendar.getInstance();
cal.setTime( this );
// Jump back to 2010, this needs to be implemented more thoroughly in order
// to support dates crossing calendar year boundaries
cal.set( Calendar.YEAR, 2010 );
setTime( cal.getTimeInMillis() );
}
}
JSpinner notWorkingSpinner = new JSpinner(m2);
JSpinner.DateEditor dateEditor = new JSpinner.DateEditor(notWorkingSpinner);
DateFormatter formatter = new DateFormatter( format );
notWorkingSpinner.setEditor(dateEditor);
dateEditor.getTextField().setFormatterFactory( new DefaultFormatterFactory( formatter ) );
formatter.setValueClass( DateThatAddsYear.class ); // Tell it to use a different value class!
使用我们的日期修正手动设置微调器:
public static class DateThatAddsYear extends Date {
public DateThatAddsYear( String time ) {
super( time );
Calendar cal = GregorianCalendar.getInstance();
cal.setTime( this );
// Jump back to 2010, this needs to be implemented more thoroughly in order
// to support dates crossing calendar year boundaries
cal.set( Calendar.YEAR, 2010 );
setTime( cal.getTimeInMillis() );
}
}
JSpinner notWorkingSpinner = new JSpinner(m2);
JSpinner.DateEditor dateEditor = new JSpinner.DateEditor(notWorkingSpinner);
DateFormatter formatter = new DateFormatter( format );
notWorkingSpinner.setEditor(dateEditor);
dateEditor.getTextField().setFormatterFactory( new DefaultFormatterFactory( formatter ) );
formatter.setValueClass( DateThatAddsYear.class ); // Tell it to use a different value class!
很难看,但很管用
另外,如果您想查看JRE源代码,我建议您查看InternationalFormatter(DateFormatter的超类)的公共方法
stringToValue(字符串文本)
。这有点难看,但我已经成功了
这是代码。我只是负责JSpinner的addChangeListener中的范围验证
import java.awt.GridLayout;
import java.util.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class T extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
public T() {
super(new GridLayout(2, 2));
init();
}
public Calendar end;
public JSpinner notWorkingSpinner;
private void init() {
Calendar start = GregorianCalendar.getInstance();
end = GregorianCalendar.getInstance();
start.clear();
end.clear();
start.set(Calendar.YEAR, 2010);
end.set(Calendar.YEAR, 2010);
end.add(Calendar.HOUR_OF_DAY, 12);
SpinnerDateModel m1 =
new SpinnerDateModel(start.getTime(), start.getTime(),
end.getTime(), Calendar.MILLISECOND);
SpinnerDateModel m2 = new SpinnerDateModel();
m2.setValue(start.getTime());
JSpinner workingSpinner = new JSpinner(m1);
workingSpinner.setEditor(
new JSpinner.DateEditor(workingSpinner,
"yyyy HH:mm:ss.SSS"));
notWorkingSpinner = new JSpinner(m2);
notWorkingSpinner.setEditor(
new JSpinner.DateEditor(notWorkingSpinner,
"HH:mm:ss.SSS"));
notWorkingSpinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
SpinnerModel dateModel = notWorkingSpinner.getModel();
if(dateModel instanceof SpinnerDateModel){
Date check = ((SpinnerDateModel)dateModel).getDate();
Calendar checkCal = GregorianCalendar.getInstance();
checkCal.setTime(check);
checkCal.set(Calendar.YEAR, end.get(Calendar.YEAR));
checkCal.set(Calendar.MONTH, end.get(Calendar.MONTH));
checkCal.set(Calendar.DAY_OF_MONTH, end.get(Calendar.DAY_OF_MONTH));
if(checkCal.get(Calendar.HOUR_OF_DAY) == 23){
dateModel.setValue(start.getTime());
} else if(checkCal.getTime().compareTo(end.getTime()) > 0){
dateModel.setValue(end.getTime());
}
}
}
});
add(new JLabel("Working"));
add(workingSpinner);
add(new JLabel("!Working"));
add(notWorkingSpinner);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new T());
frame.pack();
frame.setVisible(true);
}
}
这是因为m2将不再具有所需的结束时间。正确,这无法在12:00:00.000停止。很像没有在模型中设置end。另外,由于某些原因,您的示例也不会向后旋转。更新--问题比我最初认为的要深刻得多。关于1970 Andy的好理解。我用一个快速且更干净的方法使它完全工作。删除所有原始日历代码,改用以下代码:GregorianCalendar start=new GregorianCalendar(1970,Calendar.JANUARY,1,0,0);GregorianCalendar end=新的GregorianCalendar(1970年,日历1月1日、12日、0日、0日);是的,这也很有效,但使用这种解决方案,您只能在一年内的某个日期内使用,也就是说,如果12月31日是您的开始日期。。您将无法过渡到下一年的1月1日!如果你正确地实现了你的自定义类,你可以允许跨越几年的日期。当你向后旋转时,它不会停止。我想这只是另一张支票。是的,我同意。我只是在想最高级别的检查。我们只需要为“开始”添加一个复选框。我修正了答案以适应低端限制。