1

I am using couple of JSpinners in my project who display the hour and minutes. When the JSpinner is incremented or decremented i have to save the value to the database. But the problem is that the JSpinners are giving me old values. eg- If the time displayed is 09:30 and i increment the time to 10:30, I am getting 09:30 as the returned value. I am using following code

UPDATED 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);
    }
}

if i am using tf.getText() i am getting the old value twice but if i am using spinner.getValue I am getting the new value but it is in long format

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

How should i format spinner to give only 11:18 ?

Rohan Kandwal
  • 9,112
  • 8
  • 74
  • 107
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Jan 22 '13 at 04:13
  • Not sure if [this](http://stackoverflow.com/questions/3949382/jspinner-value-change-events) helps but this might be what you're looking for. – supersam654 Jan 22 '13 at 04:16
  • @AndrewThompson I would love to but the code is too big and other parts are unnecessary in regards to my problem – Rohan Kandwal Jan 22 '13 at 04:18
  • *"other parts are unnecessary"* Right, so remove them to make the SSCCE. – Andrew Thompson Jan 22 '13 at 04:19
  • The problem is, when you first change the value, it's changing the date, year and time (hence you're getting more then one change event). Once it's changed, it's fine, you get one – MadProgrammer Jan 22 '13 at 04:21
  • @AndrewThompson ok i will make a seperate new project for this problem and then update the code. :) – Rohan Kandwal Jan 22 '13 at 04:22
  • @MadProgrammer ok but i am still getting a return of the old value that is the main problem. AndrewThompson suggested to post a sscce so i am making a new project for the problem and then update the code. – Rohan Kandwal Jan 22 '13 at 04:24
  • 1
    I think it has to do with your `SimpleDateFormat`, it appears to be stripping the date information out of the return value... – MadProgrammer Jan 22 '13 at 04:30
  • 1
    As far as I can tell, the `stringToValue` method of the formatter has no context for which to set the date portion of the `Date` object, so when it converts the time value, the date portion is reset back to 0 – MadProgrammer Jan 22 '13 at 04:38
  • @AndrewThompson posted sscce please have a look – Rohan Kandwal Jan 22 '13 at 04:53
  • @MadProgrammer updated the code please check – Rohan Kandwal Jan 22 '13 at 04:53
  • @RohanKandwal The problem still remains. When the formatter converts the `String` value to a `Date`, it's stripping of the "date" portion of the `Date`. How to fix it, I have absolutely no idea. – MadProgrammer Jan 22 '13 at 05:18
  • @MadProgrammer Is there any other way to get only hh:mm from the spinner? – Rohan Kandwal Jan 22 '13 at 05:29
  • @RohanKandwal The only things that come to mind, is you need to maintain the `Date` separately, when the change event is fired, you need to extract the hour and min values from the value from the spinner and merge them with that of the date. You would need to then determine if the value has changed in any way and take action on as required. The other choice you have is to put two spinners onto a panel, one representing the hour and one representing the minute... – MadProgrammer Jan 22 '13 at 05:33
  • @MadProgrammer can you suggest the way to maintain date seperatly as you have suggested? There must be a way to extract hh:mm from the spinner somehow, true? May be some other member post a solution soon :) – Rohan Kandwal Jan 22 '13 at 06:15

2 Answers2

3

You could maintain a "master date" which you re-merge the time value back into on each stateChanged event.

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());
        }

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • i think the answerhe want is "format spinner to give only 11:18",your solution give him the same result as before, like "Tue Jan 22 04:17:54 CST 2013". – snow8261 Jan 22 '13 at 13:22
  • @snow8261 Your are probably right, this answer is in response to a request of the OP. I may have been getting confused of the term "original". I added a simple `getTime` method which uses a `SimpleDateFormat` to format the fields `Date` value to a time `String` – MadProgrammer Jan 22 '13 at 20:51
2

Java swing use a MVC pattern, so it is the same in JSpinner. If you look into JSpinner source code, you will find that the getValue() method is actually call getModel().getValue(), so it is calling the model's getValue. and the model you use is SpinnerDateModel, and the value of it will be Date Object,when you print the Date object, it will display the default format like "Thu Jan 01 11:18:00 IST 1970", if your want to get something like "11:18", you will need to format it yourself.like

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

You may wonder why tf.getText() only get the old value, because after the ChangeEvent on the spinner occurs, a PropertyChangeEvent on the tf will occurs,will set the new value to it. Of course, you can listen to tf like tf.addPropertyChangeListener. but i will suggest use the solution above.

snow8261
  • 939
  • 2
  • 14
  • 34