Search code examples
javaswingjtextfieldjslider

Java: link JSlider and JTextfield for float value


what is the best and easiest way to link a JSlider and a JTextField so that if one changes, the other gets updated too, but there is no recursive loop?

thanks!


Solution

  • Here's a quick and dirty demo:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.event.*;
    
    public class Main {
        public static void main(String[] args) {
            final JFrame frame = new JFrame();
            final JTextField text = new JTextField(20);
            final JSlider slider = new JSlider(0, 100, 0);
            slider.addChangeListener(new ChangeListener(){
                @Override
                public void stateChanged(ChangeEvent e) {
                    text.setText(String.valueOf(slider.getValue()));
                }
            });
            text.addKeyListener(new KeyAdapter(){
                @Override
                public void keyReleased(KeyEvent ke) {
                    String typed = text.getText();
                    slider.setValue(0);
                    if(!typed.matches("\\d+") || typed.length() > 3) {
                        return;
                    }
                    int value = Integer.parseInt(typed);
                    slider.setValue(value);
                }
            });
            frame.setLayout(new BorderLayout());
            frame.add(text, BorderLayout.NORTH);
            frame.add(slider, BorderLayout.CENTER);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
            frame.pack();
        }
    }
    

    EDIT

    And if you want to use floats (as the title suggests), you could extends the JSlider class like this:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.event.*;
    import java.text.DecimalFormat;
    
    public class Main {
        public static void main(String[] args) {
            final DecimalFormat df = new DecimalFormat("0.####");
            final JFrame frame = new JFrame();
            final JTextField text = new JTextField(20);
            final DoubleJSlider slider = new DoubleJSlider(0, 100, 0, 1000);
            slider.addChangeListener(new ChangeListener(){
                @Override
                public void stateChanged(ChangeEvent e) {
                    text.setText(df.format(slider.getScaledValue()));
                }
            });
            text.addKeyListener(new KeyAdapter(){
                @Override
                public void keyReleased(KeyEvent ke) {
                    String typed = text.getText();
                    slider.setValue(0);
                    if(!typed.matches("\\d+(\\.\\d*)?")) {
                        return;
                    }
                    double value = Double.parseDouble(typed)*slider.scale;
                    slider.setValue((int)value);
                }
            });
            frame.setLayout(new BorderLayout());
            frame.add(text, BorderLayout.NORTH);
            frame.add(slider, BorderLayout.CENTER);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
            frame.pack();
        }
    }
    
    class DoubleJSlider extends JSlider {
    
        final int scale;
    
        public DoubleJSlider(int min, int max, int value, int scale) {
            super(min, max, value);
            this.scale = scale;
        }
    
        public double getScaledValue() {
            return ((double)super.getValue()) / this.scale;
        }
    }
    

    The example above denotes the interval between 0 and 0.1 in 100 steps.

    This (again) is just a quick and dirty example, but might help you on your way.