Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Odd SpinnerNumberModel behavior in Java

I'm trying to setup a JSpinner using a SpinnerNumberModel with value = 0.0005, min = 0.0, max = 1.0, and step size = 0.0005. However, when I create a spinner with these parameters I observe very strange behavior. Rather than starting at 0.0005 and increasing by 0.0005 with each click of the up arrow, the value seems to stick at 0.

To make sure this isn't just a formatting issue, I printed out the value of the spinner after each change event. Surely enough, for each click of the up arrow, the console shows the value as 0 and then 0.0005, regardless how many times the spinner has been clicked.

Below is the code I've used to test this, including a spinner with slightly different values that works just fine for comparison purposes.

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

public class Main {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(200, 80);
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        final JSpinner spinner1 = new JSpinner(new SpinnerNumberModel(0.0005, 0.0, 1.0, 0.0005));
        final JSpinner spinner2 = new JSpinner(new SpinnerNumberModel(0.05, 0.0, 1.0, 0.05));
        panel.add(spinner1, BorderLayout.NORTH);
        panel.add(spinner2, BorderLayout.SOUTH);
        frame.add(panel);
        spinner1.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                System.out.println("spinner1: " + ((Number) spinner1.getValue()).doubleValue());
            }
        });
        spinner2.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                System.out.println("spinner2: " + ((Number) spinner2.getValue()).doubleValue());
            }
        });
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

}

Can anyone explain to me why spinner2 works as intended, but spinner1 does not?

Thanks.

Edit: Thanks to Peter for pointing out that the formatting of the spinner's text field actually has an effect on the stored value. To get the first spinner to work as intended, I added the line: spinner1.setEditor(new JSpinner.NumberEditor(spinner1, "0.0000"));.

like image 333
David Thielke Avatar asked Dec 26 '11 08:12

David Thielke


1 Answers

the problem is this in the JFormattedTextField used by the spinner. In that editor you can find:

public void commitEdit() throws ParseException {
    AbstractFormatter format = getFormatter();

    if (format != null) {
        setValue(format.stringToValue(getText()), false, true);
    }
}

your spinner display 0.0005 as 0.0, if you increment it first put 0.0 in your model and then increments to 0.0005, you event actually captures it but your textfield only sees 0.0

so solution will be to change the formatting of the spinner textfield.

you can overide the editor

final JSpinner spinner1 = new JSpinner(new SpinnerNumberModel(0.0005, 0.0, 1.0, 0.0005)) {
      @Override
      protected JComponent createEditor( SpinnerModel model )
      {
        return new NumberEditor(this, "0.0000");//needed decimal format
      }
    };
like image 77
Peter Avatar answered Oct 07 '22 17:10

Peter