Search code examples
javajsliderjspinner

Changing JSlider value to JSpinner value and vice versa on change


I have a JSlider object named quantitySl and a JSpinner object named quantitySp. When someone changes the spinner I want to change the slider to the same value and vice versa.

The initialization of the objects is as follows:

SpinnerNumberModel quantityLimiter = new SpinnerNumberModel(1, 0, 20, 1); 
JSpinner quantitySp = new JSpinner(quantityLimiter);
JSlider quantitySl = new JSlider(0,20,1);
quantitySl.addChangeListener(this);
quantitySp.addChangeListener(this);

Here is the code with which I'm trying to change the values:

@Override
public void stateChanged(ChangeEvent ce) {
        if(ce.getSource()==quantitySp){
            quantitySp.setValue(quantitySl.getValue());
        }
        else if(ce.getSource()==quantitySl){
            quantitySl.setValue((int) quantitySp.getValue());
        }
}

The problem is that changing the value of the spinner triggers its statechanged event which results in locking of both those input fields. How can I solve this?


Solution

  • Try to add separate listener for each component like this:

    import java.awt.BorderLayout;
    import javax.swing.JFrame;
    import javax.swing.JSlider;
    import javax.swing.JSpinner;
    import javax.swing.SpinnerNumberModel;
    import javax.swing.SwingUtilities;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    
    @SuppressWarnings("serial")
    public class Main extends JFrame
    {
        private JSlider slider;
        private JSpinner spinner;
        private int min, max;
    
        public Main()
        {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setBounds(100, 100, 400, 200);
            initializeComponents();
            setVisible(true);
        }
    
        public void initializeComponents()
        {
            min = 0;
            max = 100;
            slider = new JSlider(JSlider.HORIZONTAL, min, max, min);
            slider.setMajorTickSpacing(10);
            slider.setMinorTickSpacing(1);
            slider.setPaintTicks(true);
            slider.setPaintLabels(true);
            spinner = new JSpinner(new SpinnerNumberModel(min, min, max, 1));
    
            slider.addChangeListener(new ChangeListener()
            {
                @Override
                public void stateChanged(ChangeEvent e)
                {
                    spinner.setValue(slider.getValue());
                }
            });
    
            spinner.addChangeListener(new ChangeListener()
            {
                @Override
                public void stateChanged(ChangeEvent e)
                {
                    slider.setValue((int) spinner.getValue());
                }
            });
    
            add(slider, BorderLayout.NORTH);
            add(spinner, BorderLayout.SOUTH);
        }
    
        public static void main(String[] args)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
    
                    try
                    {
                        UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
                    }
                    catch (ClassNotFoundException | InstantiationException
                            | IllegalAccessException
                            | UnsupportedLookAndFeelException e)
                    {
                    }
                    new Main();
                }
            });
        }
    }