简体   繁体   中英

Java JSpinner increase value with down arrow

I have a JSpinner that has all integers as model . I want it's value to increase with the down arrow and value to decrease with up arrow,which is the exact opposite of the default usage.

I have already done this using a variable that has the previous value and added a Change Listener . Whenever a value changes i compare it to the previous. If it's about to increase i instead decrease it and vice versa.

I wanted to know if there is another way of doing it. Like a listener who knows which arrow is pressed.

SpinnerNumberModel model = new SpinnerNumberModel(5, 1, 100, -1); // Note: -ve step

Andrew's answer is the way to go. This is another way to achieve it via a ChangeListener , since you mentioned it.

A ChangeListener fires every time the value changes in the spinner field.

The steps are:

  1. Keep a field reference of its current value.
  2. Detect the new value in listener
  3. If the new value is higher than the old value, it means the ↑ arrow pressed
  4. Otherwise, it means the ↓ arrow pressed
  5. According to the change, set the opposite value

An SSCCE of what I mean:

public class SpinnerExample extends JFrame {
    private int oldValue;

    public SpinnerExample() {
        super("");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        JSpinner spinner = new JSpinner();
        spinner.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                int newValue = (int) spinner.getValue();
                spinner.removeChangeListener(this);
                if (newValue > oldValue) //next value button pressed
                    spinner.setValue(oldValue - (newValue - oldValue));
                else
                    spinner.setValue(oldValue + (oldValue - newValue));
                oldValue = (int) spinner.getValue();
                spinner.addChangeListener(this);
            }
        });
        add(spinner);

        setLocationByPlatform(true);
        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new SpinnerExample().setVisible(true));
    }
}

Note that the listener is removed before changing the value and after the change is added again. If you dont remove-change-add the listener, you will end up with a StackOverFlow error since changing the value will fire the listener again and again.

Also, remember that this in line spinner.removeChangeListener(this); refers to the ChangeListener . Converting this listener to a lambda expression:

spinner.addChangeListener(e -> {
    int newValue = (int) spinner.getValue();
    spinner.removeChangeListener(this);
    if (newValue > oldValue) //next value button pressed
        spinner.setValue(oldValue - (newValue - oldValue));
    else
        spinner.setValue(oldValue + (oldValue - newValue));
    oldValue = (int) spinner.getValue();
    System.out.println("oldValue:" + oldValue);
    spinner.addChangeListener(this);
});

you will not able to remove the listener, since the this will be a reference to SpinnerExample instance and not the listener. Long story short, keep it an anonymous class and not a lambda.

Another way to accomplish is to switch the handlers/listeners of these buttons (probably reflection will have to interfere), but it will require a lot more effort. Plus there is no guarantee that will work for other look and feels, since they are initiated in <LookAndFeel> - ComboBoxUI .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM