6

2010 年 1 月 1 日 00:00:00.000 に開始する SpinnerDateModel を使用する JSpinner があり、終了日は 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);
    }
}
4

3 に答える 3

5

JRE ソースをかなり掘り下げた後、スピナーが実際の日付ではなくテキスト値によって裏付けられていることを発見しました。上下のスピン ボタンを押すと、値が解析され、最小値と最大値と比較されます。形式には年がないため、日付は常に 1970 年で解析されます。これは、エポックからの年オフセット 0 です。これにより、スピナーをスピンしようとすると、常に範囲外エラーが返されます。

最も簡単な解決策は、単純に 2010 年ではなく 1970 年を年として使用することです。ただし、最初の日付が 1970 年末である場合、スピナーはユーザーが 1971 年 1 月にロールオーバーすることを許可しません (代わりに、最初に戻る可能性があります)。 1970年)。

もう 1 つのソリューションは、暦年の境界にまたがる日付に対応できます。ただし、それほど単純ではありません (またはきれいではありません)。JRE では、DateFormatter が日付文字列を解析するときに、単一の String パラメータ コンストラクタを使用してクラスを動的にインスタンス化します。この文字列は、スピナーからの日付です。デフォルトでは、このクラスは Date またはそのサブクラスです。日付比較が実行される前に年を修正する独自の 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!

醜いですが、うまくいきます。

また、JRE ソースを調べたい場合はstringToValue(String text)、InternationalFormatter (DateFormatter のスーパークラス) のパブリック メソッドを参照することをお勧めします。

于 2010-10-08T21:52:55.753 に答える
0

それが機能しない理由はわかりませんが、 m2 の宣言を次のように変更すると:

SpinnerDateModel m2 = 新しい SpinnerDateModel(); m2.setValue(start.getTime());

できます。

于 2010-10-08T21:28:54.907 に答える
0

これはちょっと醜いですが、うまくいきました。

これがコードです。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);
    }
}
于 2010-10-08T22:57:52.417 に答える