JSpinner дает старые значения

Я использую пару JSpinners в своем проекте, которые отображают часы и минуты. Когда JSpinner увеличивается или уменьшается, я должен сохранить значение в базе данных. Но проблема в том, что JSpinners дают мне старые значения. Например, если отображаемое время равно 09:30, и я увеличиваю время до 10:30, я получаю 09:30 в качестве возвращаемого значения. Я использую следующий код

ОБНОВЛЕНО SSCCE

package spinnerupdation;

import java.awt.Container;
import java.awt.FlowLayout;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerDateModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.DateFormatter;
import javax.swing.text.DefaultFormatterFactory;

/**
 *
 * @author Rohan Kandwal
 */
public class SpinnerUpdation extends JFrame{
 public JSpinner spinner;
    SpinnerUpdation(){
        Container pane=this.getContentPane();
        JPanel panel=new JPanel();
        panel.setLayout(new FlowLayout());
        SpinnerDateModel model=new SpinnerDateModel();
        model.setCalendarField(Calendar.HOUR);
        spinner=new JSpinner();
        spinner.setModel(model);
        spinner.setEditor(new JSpinner.DateEditor(spinner,"hh:mm"));
        panel.add(spinner);
        pane.add(panel);
        spinner.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                        JFormattedTextField tf = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField();
                        DefaultFormatterFactory factory = (DefaultFormatterFactory) tf.getFormatterFactory();
                        DateFormatter formatter = (DateFormatter) factory.getDefaultFormatter();

                        // Change the date format to only show the hours
                        formatter.setFormat(new SimpleDateFormat("hh:mm"));
                        //formatter.setCommitsOnValidEdit(true);

                System.out.println(spinner.getValue());
                //System.out.println(tf.getText());
            }
        });


            }
    public static void main(String[] args) {
        SpinnerUpdation ss=new SpinnerUpdation();

        ss.setDefaultCloseOperation(ss.EXIT_ON_CLOSE);
        ss.setSize(574, 445);
     //ss.pack();

     ss.setLocationRelativeTo(null);
     ss.setResizable(false);
     ss.setVisible(true);
    }
}

если я использую tf.getText(), я получаю старое значение дважды, но если я использую spinner.getValue, я получаю новое значение, но оно в длинном формате

Thu Jan 01 10:18:00 IST 1970
Thu Jan 01 11:18:00 IST 1970

Как мне отформатировать счетчик, чтобы он выдавал только 11:18?


person Rohan Kandwal    schedule 22.01.2013    source источник
comment
Чтобы быстрее получить помощь, опубликуйте SSCCE.   -  person Andrew Thompson    schedule 22.01.2013
comment
Не уверен, поможет ли это, но это может быть то, что вы ищете.   -  person supersam654    schedule 22.01.2013
comment
@AndrewThompson Я бы с удовольствием, но код слишком большой, а другие части не нужны для моей проблемы.   -  person Rohan Kandwal    schedule 22.01.2013
comment
другие части не нужны Верно, поэтому удалите их, чтобы сделать SSCCE.   -  person Andrew Thompson    schedule 22.01.2013
comment
Проблема в том, что когда вы впервые меняете значение, оно меняет дату, год и время (следовательно, вы получаете более одного события изменения). Как только это изменилось, все в порядке, вы получите один   -  person MadProgrammer    schedule 22.01.2013
comment
@AndrewThompson хорошо, я сделаю отдельный новый проект для этой проблемы, а затем обновлю код. :)   -  person Rohan Kandwal    schedule 22.01.2013
comment
@MadProgrammer хорошо, но я все еще получаю возврат старого значения, что является основной проблемой. Эндрю Томпсон предложил опубликовать sscce, поэтому я создаю новый проект для решения проблемы, а затем обновляю код.   -  person Rohan Kandwal    schedule 22.01.2013
comment
Я думаю, что это связано с вашим SimpleDateFormat, похоже, он удаляет информацию о дате из возвращаемого значения...   -  person MadProgrammer    schedule 22.01.2013
comment
Насколько я могу судить, метод форматирования stringToValue не имеет контекста, для которого можно установить часть даты объекта Date, поэтому, когда он преобразует значение времени, часть даты сбрасывается обратно на 0   -  person MadProgrammer    schedule 22.01.2013
comment
@AndrewThompson опубликовал sscce, пожалуйста, посмотрите   -  person Rohan Kandwal    schedule 22.01.2013
comment
@MadProgrammer обновил код, пожалуйста, проверьте   -  person Rohan Kandwal    schedule 22.01.2013
comment
@RohanKandwal Проблема все еще остается. Когда форматер преобразует значение String в Date, он удаляет часть даты из Date. Как это исправить, я совершенно не представляю.   -  person MadProgrammer    schedule 22.01.2013
comment
@MadProgrammer Есть ли другой способ получить от счетчика только чч: мм?   -  person Rohan Kandwal    schedule 22.01.2013
comment
@RohanKandwal Единственное, что приходит на ум, это то, что вам нужно поддерживать Date отдельно, когда событие изменения запускается, вам нужно извлечь значения часа и минуты из значения из счетчика и объединить их со значением даты. Затем вам нужно будет определить, изменилось ли значение каким-либо образом, и предпринять необходимые действия. Другой вариант, который у вас есть, это поместить два счетчика на панель, один из которых представляет часы, а другой - минуты...   -  person MadProgrammer    schedule 22.01.2013
comment
@MadProgrammer Можете ли вы предложить способ сохранения даты отдельно, как вы предложили? Должен же быть способ извлечь чч:мм из счетчика, верно? Может быть, какой-то другой участник опубликует решение в ближайшее время :)   -  person Rohan Kandwal    schedule 22.01.2013


Ответы (2)


Свинг Java использует шаблон MVC, поэтому в JSpinner он такой же. Если вы посмотрите на исходный код JSpinner, вы обнаружите, что метод getValue() на самом деле вызывает getModel().getValue(), поэтому он вызывает метод getValue модели. и модель, которую вы используете, - SpinnerDateModel, и ее значением будет Date Object, когда вы печатаете объект Date, он будет отображать формат по умолчанию, например «Чт, 01 января, 11:18:00 IST 1970», если вы хотите получить что-то вроде "11:18", вам нужно будет отформатировать его самостоятельно.

 SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
 System.out.println(sdf.format(spinner.getValue()) );

Вы можете задаться вопросом, почему tf.getText() получает только старое значение, потому что после того, как произойдет ChangeEvent на счетчике, произойдет PropertyChangeEvent на tf, установит для него новое значение. Конечно, вы можете слушать tf, например tf.addPropertyChangeListener. но я предлагаю использовать решение выше.

person snow8261    schedule 22.01.2013
comment
спасибо, ваш код сработал как шарм, и ваше описание тоже было очень хорошим. - person Rohan Kandwal; 22.01.2013

Вы можете поддерживать «основную дату», в которую вы повторно объединяете значение времени для каждого события stateChanged.

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            add(new DateSpinner(new Date()));
        }

    }

    public class DateSpinner extends JSpinner {

        private Date masterDate;

        public DateSpinner(Date date) {
            super(new SpinnerDateModel());
            this.masterDate = date;
            SpinnerDateModel model = (SpinnerDateModel) getModel();
            model.setCalendarField(Calendar.HOUR);
            setEditor(new JSpinner.DateEditor(this, "hh:mm"));
            JFormattedTextField tf = ((JSpinner.DefaultEditor) getEditor()).getTextField();
            DefaultFormatterFactory factory = (DefaultFormatterFactory) tf.getFormatterFactory();
            DateFormatter formatter = (DateFormatter) factory.getDefaultFormatter();

            formatter.setFormat(new SimpleDateFormat("hh:mm"));

            setValue(date);

            addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {

                    Calendar cal = Calendar.getInstance();
                    cal.setTime(masterDate);

                    Calendar time = Calendar.getInstance();
                    time.setTime((Date) getValue());

                    cal.set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY));
                    cal.set(Calendar.MINUTE, time.get(Calendar.MINUTE));

                    masterDate = cal.getTime();

                    System.out.println(masterDate);

                }

            });
        }

        public String getTime() {
            return new SimpleDateFormat("hh:mm").format((Date)getValue());
        }

    }

}
person MadProgrammer    schedule 22.01.2013
comment
Я думаю, что ответ, который он хочет, - это форматирование счетчика, чтобы он давал только 11:18, ваше решение дает ему тот же результат, что и раньше, например, вторник, 22 января, 04:17:54 CST 2013. - person snow8261; 22.01.2013
comment
@snow8261 Snow8261 Возможно, вы правы, этот ответ дан в ответ на запрос ОП. Я, возможно, запутался в термине оригинал. Я добавил простой метод getTime, который использует SimpleDateFormat для форматирования значений полей Date во время String - person MadProgrammer; 23.01.2013