2

I want to create a JSlider with only four possible values: 10 (min), 30, 60, and 100 (max). Is it possible to create one that can "snap" to only these values? If so, can you please provide an example? Thanks!

BJ Dela Cruz
  • 5,194
  • 13
  • 51
  • 84
  • Is there a reason you want to have inconsistent incremented ticks? 10,40,70,100 doesn't meet your need? – JBuenoJr Jul 30 '13 at 00:09
  • 1
    Yes you can. You'll need a custom `DefaultBoundedRangeModel` to manage the values and a implementation of the `BasicSliderUI` to manage the stepping...about there I stopped trying... – MadProgrammer Jul 30 '13 at 00:26

2 Answers2

5

The following example is probably the easiest way to do what you're looking for. Note that you can't simply override getValue() on the JSlider subclass to return the domain-specific value, because that is problematic for the underlying JSlider/BasicSliderUI implementation. In this example, I've defined a custom getDomainValue() to return the domain-specific value (10, 30, 60, or 100) based on the slider tick position.

package example.stackoverflow;

import java.util.Hashtable;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class SteppingSliderExample
{
    public static class SteppingSlider extends JSlider
    {
        private static final long serialVersionUID = -1195270044097152629L;
        private static final Integer[] VALUES = { 10, 30, 60, 100 };
        private static final Hashtable<Integer, JLabel> LABELS = new Hashtable<>();
        static
        {
            for(int i = 0; i < VALUES.length; ++i)
            {
                LABELS.put(i, new JLabel(VALUES[i].toString()));
            }
        }

        public SteppingSlider()
        {
            super(0, VALUES.length - 1, 0);
            setLabelTable(LABELS);      
            setPaintTicks(true);
            setPaintLabels(true);
            setSnapToTicks(true);
            setMajorTickSpacing(1);
        }

        public int getDomainValue()
        {
            return VALUES[getValue()];
        }
    }

    public static void createAndShowGUI()
    {
        JFrame frame = new JFrame("SteppingSlider");
        frame.setSize(500, 120);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final SteppingSlider steppingSlider = new SteppingSlider();
        final String labelPrefix = "Slider value: ";
        final JLabel output = new JLabel(labelPrefix + steppingSlider.getDomainValue());
        steppingSlider.addChangeListener(new ChangeListener()
        {           
            @Override
            public void stateChanged(ChangeEvent evt)
            {
                output.setText(labelPrefix + steppingSlider.getDomainValue());
            }
        });
        frame.getContentPane().setLayout(
                new BoxLayout(frame.getContentPane(), 
                        BoxLayout.Y_AXIS));     
        frame.getContentPane().add(steppingSlider);
        frame.getContentPane().add(output);
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}
Buzz Killington
  • 1,039
  • 9
  • 14
-1

Write a subclass of JSlider that overrides getValue() and maps e.g. [1,2,3,4] (original) to [10,30,60,100]. Simplest solution that comes to my mind.

  • 1
    This is very dangerous as this will change the functionality of the `JSlider` (it internally also accesses it's `getValue()` method). – brimborium Nov 23 '15 at 22:52