JSpinner.DateEditor必须包括年份,即使开始和结束是同一年

ini*_*ero 6 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 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

And*_*ndy 5

在JRE源代码中进行了大量挖掘之后,我发现微调器由文本值而不是真实日期支持.当您按下向上和向下旋转按钮时,将解析该值,然后将其与最小值和最大值进行比较.由于您的格式没有一年,因此日期将被解析,年份始终为1970年,即年份偏离0的年份.当您尝试旋转时,这会导致微调器始终返回超出范围的错误.

最快的解决方案是简单地使用1970作为你的年份而不是2010年.但是,如果你的初始日期是在1970年底,那么微调器就不会让你的用户翻到1971年1月(相反它可能会跳回到开头1970年).

另一种解决方案可以适应跨越日历年边界的日期.但是,它并不那么简单(或漂亮).在JRE中,当DateFormatter解析日期字符串时,它使用单个String参数构造函数动态地实例化一个类.该字符串是微调器的日期.默认情况下,此类是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() );
 }
}
Run Code Online (Sandbox Code Playgroud)

使用我们的日期修复手动设置微调器:

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!
Run Code Online (Sandbox Code Playgroud)

丑陋,但它的工作原理.

此外,如果你想在JRE源代码中寻找,我建议看一下stringToValue(String text)InternationalFormatter 的公共方法(DateFormatter的超类).

  • 关于1970年安迪的好消息.我完全使用一个快速和更清洁的修复工作.删除所有原始日历代码,并使用此代码:GregorianCalendar start = new GregorianCalendar(1970,Calendar.JANUARY,1,0,0,0); GregorianCalendar end = new GregorianCalendar(1970,Calendar.JANUARY,1,12,8,0); (2认同)