Cant change date values on Spinner

620 views Asked by At

I want to write some code that receives input from two JSpinners. I want it so that I can change the values of the JSpinners and get the string value from whats shown in the Spinners. I did this by adding a ChangeListener. However in the actual application I can't change the values on the spinner, or in other words, I can't move the Spinner up or down

import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


  public class SalesApplication extends JFrame {

    SpinnerModel model1;
   JSpinner spinner1;
   SpinnerModel model2;
   JSpinner spinner2;

   public SalesApplication(){

        model1 = new SpinnerDateModel();
           spinner1 = new JSpinner(model1);


 //Sub any date you want
           Date firstDate1 = null;
           model1 = new SpinnerDateModel(firstDate1, null, null, Calendar.DAY_OF_MONTH);


            class SpinnerListener1 implements ChangeListener {
             public void stateChanged(ChangeEvent e) {
             JSpinner spinner = (JSpinner) e.getSource();
             initialDate = (String) spinner.getValue();
      }
         }; 
          spinner1.addChangeListener(new SpinnerListener1());


           model2 = new SpinnerDateModel();
           spinner2 = new JSpinner(model2);
           Date firstDate2 = null ;
           model2 = new SpinnerDateModel(firstDate2, null, null, Calendar.DAY_OF_MONTH);

            class SpinnerListener2 implements ChangeListener {
           public void stateChanged(ChangeEvent e) {
             JSpinner spinner = (JSpinner) e.getSource();
             endDate = (String) spinner.getValue();
      }
         };
    spinner2.addChangeListener(new SpinnerListener2());
       JPanel rightPanel = new JPanel();
       rightPanel.add(spinner1);
       rightPanel.add(spinner2);
       add(rightPanel, java.awt.BorderLayout.EAST);
 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       setSize(600, 300);                       
       setVisible(true);
2

There are 2 answers

2
DontKnowMuchBut Getting Better On

You're creating two SpinnerDateModel's with this code:

model1 = new SpinnerDateModel(); // SpinnerDateModel (1)
spinner1 = new JSpinner(model1);  // holds the first model
Date firstDate1 = dateObj[4];
model1 = new SpinnerDateModel(firstDate1, null, null, Calendar.DAY_OF_MONTH); // SpinnerDateModel (2)

The spinner1 JSpinner only holds the first SpinnerDateModel object, and no JSpinner holds the second one, and so that object is simply ignored and is wasted. If you need to use the 2nd model, then don't even create the first one:

// model1 = new SpinnerDateModel(); // SpinnerDateModel (1)
// spinner1 = new JSpinner(model1);
Date firstDate1 = dateObj[4];
model1 = new SpinnerDateModel(firstDate1, null, null, Calendar.DAY_OF_MONTH); // SpinnerDateModel (2)
spinner1 = new JSpinner(model1); // now holds the second model

You've the exact same problem for the model2 variable.

The key issue above is that you seem to be equating variable with the object it holds. Once you pass the SpinnerDateModel into the JSpinner, then changing the variable that your model1 SpinnerDateModel holds will have no effect on the model object held by the JSpinner itself.

1
DontKnowMuchBut Getting Better On

You seem to be guessing at how to create SpinnerDateModel objects and use them within a JSpinner. Simply, the model needs a start Date, end Date, and a value, or date to display. For example, something like so:

// current value will be *today*
private Date value = new Date();  // today

// start will be the first of the year
private Date start = new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime();

// end will be the last of the year
private Date end = new GregorianCalendar(2019, Calendar.DECEMBER, 31).getTime();

// create date model using the above values
private SpinnerDateModel dateModel1 = new SpinnerDateModel(value, start, end, Calendar.DAY_OF_MONTH);

// put into JSpinner
private JSpinner spinner1 = new JSpinner(dateModel1);    

Then in the ChangeListener, you extract a Date object from the Spinner since that is what it holds. You seem to be trying to extract a String which won't work. For example:

spinner1.addChangeListener(evt -> {
    Date currentDate = (Date) spinner1.getValue(); // holds date values
    String dateText = format.format(currentDate); // if we want to extract a String from it
    System.out.println("Current Date: " + dateText);  // display it
});

A working example could look like:

import java.awt.Dimension;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.swing.*;

@SuppressWarnings("serial")
public class SpinnerTester extends JPanel {
    // current value will be *today*
    private Date value = new Date();  // today

    // start will be the first of the year
    private Date start = new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime();

    // end will be the last of the year
    private Date end = new GregorianCalendar(2019, Calendar.DECEMBER, 31).getTime();

    // create date model using the above values
    private SpinnerDateModel dateModel1 = new SpinnerDateModel(value, start, end, Calendar.DAY_OF_MONTH);

    // put into JSpinner
    private JSpinner spinner1 = new JSpinner(dateModel1);

    public SpinnerTester() {
        // get the format from the spinner's editor
        SimpleDateFormat format = ((JSpinner.DateEditor) spinner1.getEditor()).getFormat();

        // have our spinner show the date only, and not the time
        format.applyPattern("MM/dd/yyyy");

        // add to GUI
        add(spinner1);
        setPreferredSize(new Dimension(400, 200));

        spinner1.addChangeListener(evt -> {
            Date currentDate = (Date) spinner1.getValue(); // holds date values
            String dateText = format.format(currentDate); // if we want to extract a String from it
            System.out.println("Current Date: " + dateText);  // display it
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            SpinnerTester mainPanel = new SpinnerTester();
            JFrame frame = new JFrame("Spinner Tester");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.add(mainPanel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        });
    }
}

Thanks to mKorbel's answer for showing how to format the date rendered within the JSpinner.