JSpinner.DateEditor должен включать год, даже если начало и конец года совпадают - PullRequest
6 голосов
/ 06 октября 2010

У меня есть JSpinner, использующий SpinnerDateModel, который начинается с 1 января 2010 г. 00: 00: 00.000, дата окончания - 1 января 2010 г. 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);
    }
}

Ответы [ 3 ]

5 голосов
/ 09 октября 2010

После долгих поисков в источнике JRE я обнаружил, что спиннер поддерживается текстовым значением вместо истинной даты.При нажатии кнопок прокрутки вверх и вниз значение анализируется, а затем сравнивается с минимальными и максимальными значениями.Поскольку в вашем формате нет года, даты анализируются, причем год всегда равен 1970, который смещен на 0 от эпохи.Это заставляет счетчик всегда возвращать ошибку вне диапазона, когда вы пытаетесь его вращать.

Самое быстрое решение состоит в том, чтобы просто использовать 1970 как год вместо 2010. Однако, если вашПервоначальная дата - в конце 1970 года. Спиннер не позволит вашим пользователям переноситься на январь 1971 года (вместо этого он может вернуться к началу 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() );
 }
}

Вручную настройте счетчик, используя наше исправление даты:

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).

0 голосов
/ 09 октября 2010

Это некрасиво, но у меня все получилось.

Вот код. Я просто позаботился о проверке диапазона внутри addChangeListener для JSpinner.

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);
    }
}
0 голосов
/ 09 октября 2010

Я не уверен, почему это не работает, но если вы измените объявление m2 на:

SpinnerDateModel m2 = new SpinnerDateModel (); m2.setValue (start.getTime ());

это работает.

...