Sliders
Home ] Up ] [ Sliders ] Spinners ]

 

 

A slider control allows a user to choose from a continuum of values between a minimum and maximum value.  Sliders were introduced in Java 1.4, and behave somewhat like scrollbars, except that they can be visually configured in a more pleasing way than scrollbars.

Here's an example of the use and configuration of a slider control:

package swingExamples;

import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JFrame;
import javax.swing.JSlider;
import javax.swing.SwingConstants;

/**
 * A JFrame class to demonstrate JSlider usage.
 */
class SlidersFrame extends JFrame
{
  public SlidersFrame()
  {
    setTitle("Sliders");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    Container panel = getContentPane();
    panel.setLayout( new BorderLayout() );
    
    panel.add(
        new TitlePanel("Slider Configuration"), 
                       BorderLayout.NORTH);
    
    JSlider slider = new JSlider();
    slider.setMajorTickSpacing(20);
    slider.setMinorTickSpacing(5);
    panel.add(
        new SliderPanel(slider), BorderLayout.CENTER);
    
    panel.add(
        new FeelPanel(SwingConstants.VERTICAL), 
                      BorderLayout.WEST);
    
    ValuePanel valuePanel = new ValuePanel();
    panel.add(valuePanel, BorderLayout.EAST);
    valuePanel.setValue(slider);
    // Set up change listener so we can see the value
    slider.addChangeListener(valuePanel);
    
    ControlPanel controlPanel = new ControlPanel(slider);
    panel.add(controlPanel, BorderLayout.SOUTH);
    
    pack();
  }
}

public class Sliders
{
  public static void main(String[] args)
  {
    JFrame frame = new SlidersFrame();
    frame.setVisible(true);
  }
}
package swingExamples;

import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

/**
 * A panel to display a title string
 */
public class TitlePanel extends JPanel
{
  public TitlePanel(String title)
  {
    JLabel label = 
        new JLabel(title,
                   SwingConstants.CENTER);
    label.setForeground(Color.BLUE);
    add(label);
  }
}
package swingExamples;

import java.awt.BorderLayout;
import java.awt.Color;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JSlider;

/**
 * A panel to display a JSlider component
 */
public class SliderPanel extends JPanel
{
  public SliderPanel(JSlider slider)
  {
    m_slider = slider;
    setBackground(Color.WHITE);
    setBorder(
        BorderFactory.createTitledBorder("Slider:") );
    add(m_slider);
    m_slider.setBorder(
        BorderFactory.createLineBorder(Color.BLUE));
  }
  
  ////// Private data /////
  private JSlider m_slider;
}
package swingExamples;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ValuePanel extends JPanel
    implements ChangeListener
{
  public ValuePanel()
  {
    setBorder(
        BorderFactory.createCompoundBorder(
        BorderFactory.createEmptyBorder(0, 5, 0, 5),
        BorderFactory.createTitledBorder("Value:")
        ) );
    JPanel valueContentsPanel = new JPanel();
    add(valueContentsPanel);
    valueContentsPanel.add(m_valueLabel);
  }
  
  public void setValue(JSlider slider)
  {
    m_valueLabel.setText("" + slider.getValue());
  }

  public void stateChanged(ChangeEvent event)
  {
    JSlider slider = (JSlider)event.getSource();
    setValue(slider);
  }
  
  //// Private data ////
  
  // A label that shows the current value of the slider
  private JLabel m_valueLabel =
      new JLabel("", SwingConstants.CENTER);
}
package swingExamples;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Dictionary;
import java.util.Hashtable;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;

import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;

/**
 * A control panel used to configure the layout
 * and properties of a slider component.
 */
public class ControlPanel extends JPanel
    implements ActionListener
{
  public ControlPanel(JSlider slider)
  {
    m_slider = slider;  // The slider being configured
    loadImages();       // Load the icon images
    
    setLayout( new BorderLayout() );
    setBorder(
        BorderFactory.createTitledBorder("Configure:") );
    
    // Create a panel to contain the first set of checkboxes
    JPanel checkboxPanel = new JPanel();
    add(checkboxPanel, BorderLayout.NORTH);
    // Add the checkbox controls to the checkbox panel
    checkboxPanel.add(m_ticks);
    checkboxPanel.add(m_snap);
    checkboxPanel.add(m_track);
    checkboxPanel.add(m_inverted);
    // Create a panel to contain the orientation buttons
    JPanel orientationPanel = new JPanel(
        new FlowLayout(FlowLayout.LEFT) );
    add(orientationPanel, BorderLayout.CENTER);
    JPanel orientationButtonsPanel = new JPanel();
    orientationPanel.add(orientationButtonsPanel);
    orientationButtonsPanel.setBorder(
        BorderFactory.createTitledBorder("Orientation:") );
    // Add the orientation radio buttons to the inner
    // panel, adding action listeners as we go.
    ActionListener orientationListener =
        new OrientationHandler();
    for (JRadioButton button : m_orientationButtons)
    {
      orientationButtonsPanel.add(button);
      button.addActionListener(orientationListener);
    }
    
    // Create a panel to contain the label-related stuff
    JPanel labelPanel = new JPanel();
    add(labelPanel, BorderLayout.SOUTH);
    // Add the Show labels checkbox to the label panel
    labelPanel.add(m_labels);
    
    // Create a panel to hold the label radio buttons
    // and add it to the control panel.
    JPanel labelButtonPanel = new JPanel();
    labelButtonPanel.setBorder(
        BorderFactory.createTitledBorder("Label Type:")
        );
    labelPanel.add(labelButtonPanel, BorderLayout.SOUTH);
    // Add the radio buttons to the panel, adding
    // action listeners as we go.
    ActionListener labelButtonListener =
        new LabelTypeActionHandler();
    for (JRadioButton button : m_labelButtons)
    {
      labelButtonPanel.add(button);
      button.addActionListener(labelButtonListener);
    }
  }
  
  // Required by ActionListener
  // This handles only the checkbox actions.
  public void actionPerformed(ActionEvent event)
  {
    JCheckBox box = (JCheckBox) event.getSource();
    if (box == m_ticks)
    {
      m_slider.setPaintTicks(
          m_ticks.isSelected() );
    }
    else if (box == m_snap)
    {
      m_slider.setSnapToTicks(
          m_snap.isSelected() );
    }
    else if (box == m_track)
    {
      m_slider.setPaintTrack(
          m_track.isSelected() );
    }
    else if (box == m_inverted)
    {
      m_slider.setInverted(
          m_inverted.isSelected() );
    }
    else if (box == m_labels)
    {
      m_slider.setPaintLabels(
          m_labels.isSelected() );
    }
    
    repaintFrame();
  }
  
  private void repaintFrame()
  {
    // Cause the frame to be repainted and resized
    SwingUtilities.getWindowAncestor(this).pack();    
  }
  
  ///// Private data /////
  
  private JSlider m_slider;  // The slider being configured.
  
  // Checkbox controls
  private JCheckBox m_ticks = new JCheckBox("Show Ticks");
  private JCheckBox m_snap = new JCheckBox("Snap to ticks");
  private JCheckBox m_track = new JCheckBox("Show Track", true);
  private JCheckBox m_inverted = new JCheckBox("Inverted");
  
  // Orientation radio buttons
  private ButtonGroup m_orientationGroup = new ButtonGroup();
  private static final String 
      HORIZONTAL = "Horizontal",
      VERTICAL   = "Vertical";
  private static final String[] ORIENTATION_ACTIONS =
  {
    HORIZONTAL, VERTICAL
  };
  private JRadioButton[] m_orientationButtons =
  {
    new JRadioButton(HORIZONTAL, true),
    new JRadioButton(VERTICAL)
  };
  // Add radio buttons to button group
  {
    int index = 0;
    for (JRadioButton button : m_orientationButtons)
    {
      m_orientationGroup.add(button);
      String command = ORIENTATION_ACTIONS[index++];
      button.setActionCommand(command);
    }
  }
  
  // Labels checkbox
  private JCheckBox m_labels = new JCheckBox("Show Labels");
  
  // Add listeners to checkbox controls
  {
    m_ticks.addActionListener(this);
    m_snap.addActionListener(this);
    m_track.addActionListener(this);
    m_inverted.addActionListener(this);
    m_labels.addActionListener(this);
  }
  
  // Radio button controls
  private ButtonGroup m_labelsGroup = new ButtonGroup();
  private static final String
      DEFAULT = "Default",
      CUSTOM  = "Custom",
      ICONS   = "Icons";
  private static final String[] LABEL_COMMANDS =
  {
    DEFAULT, CUSTOM, ICONS
  };
  private JRadioButton[] m_labelButtons =
  {
    new JRadioButton("Default", true),
    new JRadioButton("Custom (A,B,C...)"),
    new JRadioButton("Icons")
  };
  // Add radio buttons to button group
  {
    int index = 0;
    for (JRadioButton button : m_labelButtons)
    {
      m_labelsGroup.add(button);
      String command = LABEL_COMMANDS[index++];
      button.setActionCommand(command);
    }
  }
  
  ///// Labels for customizing the slider /////
  
  // A dictionary to hold custom JLabels for the apha labels
  private Dictionary<Integer, JLabel> m_labelTable =
      new Hashtable<Integer, JLabel>();
  // Initialize the label table
  {
    m_labelTable.put(0, new JLabel("A"));
    m_labelTable.put(20, new JLabel("B"));
    m_labelTable.put(40, new JLabel("C"));
    m_labelTable.put(60, new JLabel("D"));
    m_labelTable.put(80, new JLabel("E"));
    m_labelTable.put(100, new JLabel("F"));
  };
  
  // A dictionary to hold JLabels for the icon labels
  private Dictionary<Integer, JLabel> m_iconLabelTable =
      new Hashtable<Integer, JLabel>();
  
  /**
   * Loads the images for the above icon labels
   */
  private void loadImages()
  {
    // Image file names are relative to the current class
    final String[] iconPaths =
    {
      "images/nine.gif", "images/ten.gif",
      "images/jack.gif", "images/queen.gif",
      "images/king.gif", "images/ace.gif"
    };
    
    // Initialize the icon label table
    Class base = this.getClass();
    int i = 0;
    for (String path : iconPaths)
    {
      ImageIcon icon =
          ImageUtilities.createImageIcon(base, path);
      m_iconLabelTable.put(i, new JLabel(icon));
      i += 20;
    }
  }

  //////// Inner classes ////////
  
  /**
   * This class handles the label type radio button actions
   */
  class LabelTypeActionHandler
      implements ActionListener
  {
    public void actionPerformed(ActionEvent event)
    {
      String command =
          m_labelsGroup.getSelection().getActionCommand();
      if (command.equals(DEFAULT))
      {
        m_slider.setLabelTable(null);
        m_slider.setPaintLabels(m_labels.isSelected());
      }
      else if (command.equals(CUSTOM))
      {
        m_slider.setLabelTable(m_labelTable);
      }
      else if (command.equals(ICONS))
      {
        m_slider.setLabelTable(m_iconLabelTable);
      }
      
      // Repaint/resize frame
      repaintFrame();
    }
  }
  
  /**
   * This class handles the orientation radio
   * button actions.
   */
  class OrientationHandler
      implements ActionListener
  {
    public void actionPerformed(ActionEvent event)
    {
      String action = event.getActionCommand();
      if (action.equals(HORIZONTAL))
      {
        m_slider.setOrientation(JSlider.HORIZONTAL);
      }
      else if (action.equals(VERTICAL))
      {
        m_slider.setOrientation(JSlider.VERTICAL);
      }
      repaintFrame();
    }
  }
  
  /**
   * Main entry point, for testing
   */
  public static void main(String[] args)
  {
    JFrame frame = new JFrame();
    JPanel panel = (JPanel)frame.getContentPane();
    panel.setLayout( new BorderLayout() );
    
    JPanel sliderPanel = new JPanel();
    JSlider slider = new JSlider();
    slider.setBorder(
        BorderFactory.createLineBorder(Color.BLUE));
    slider.setMajorTickSpacing(20);
    slider.setMinorTickSpacing(5);
    sliderPanel.add(slider);

    panel.add(sliderPanel, BorderLayout.CENTER);
    panel.add( new ControlPanel(slider), BorderLayout.SOUTH );
    frame.pack();
    frame.setVisible(true);
  }
}
package swingExamples;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

/**
 * A panel that can be used to allow the 
 * user to control the current look and feel
 * of an application
 */
public class FeelPanel extends JPanel
    implements ActionListener
{
  /**
   * Creates a look and feel panel with the
   * radio boxes laid out in a horizontal 
   * orientation
   */
  public FeelPanel()
  {
    this(SwingConstants.HORIZONTAL);
  }
  
  /**
   * Creates a Look and Feel panel with the
   * radio boxes laid out in a horizontal or
   * vertical orientation, depending on the 
   * user's choice.
   * @param orientation the horizontal or vertical
   *                    orientation (allowed values:
   *                    SwingConstants.HORIZONTAL or
   *                    SwingConstants.VERTICAL)
   */
  public FeelPanel(int orientation)
  {
    GridLayout layout = null;
    if (orientation == SwingConstants.HORIZONTAL)
      layout = new GridLayout(1, m_feelButtons.length);
    else
      layout = new GridLayout(m_feelButtons.length, 1);
    JPanel feelButtonsPanel = new JPanel(layout);
    add(feelButtonsPanel);
    feelButtonsPanel.setBorder(
        BorderFactory.createTitledBorder("Look & Feel:") );
    // Add the radio buttons to the panel, adding
    // action listeners as we go.
    for (JRadioButton button : m_feelButtons)
    {
      feelButtonsPanel.add(button);
      button.addActionListener(this);
    }
  }
  
  // Required for ActionListener
  public void actionPerformed(ActionEvent event)
  {
    // Responds to the specified action by dynamically
    // changing the look and feel of the application.
    String action = event.getActionCommand();
    Window ancestor = SwingUtilities.getWindowAncestor(this);
    LookAndFeel.setLookAndFeel(action, ancestor);
    ancestor.pack();
  }
  
  ///// Private data /////
  
  // Radio buttons for showing look and feel rendering of slider
  private ButtonGroup m_feelGroup = new ButtonGroup();
  private String[] m_feelCommands =
  {
    LookAndFeel.METAL, LookAndFeel.SYSTEM, LookAndFeel.MOTIF
  };
  private JRadioButton[] m_feelButtons =
  {
    new JRadioButton(LookAndFeel.METAL, true),
    new JRadioButton(LookAndFeel.SYSTEM),
    new JRadioButton(LookAndFeel.MOTIF)
  };
  // Add radio buttons to button group
  {
    int index = 0;
    for (JRadioButton button : m_feelButtons)
    {
      if (index == 0)
        button.setSelected(true);
      m_feelGroup.add(button);
      String command = m_feelCommands[index++];
      button.setActionCommand(command);
    }
  }

  /**
   * Main entry point, for testing
   */
  public static void main(String[] args)
  {
    JFrame frame = new JFrame();
    JPanel panel = (JPanel) frame.getContentPane();
    panel.add( 
        new FeelPanel(SwingConstants.VERTICAL),
        BorderLayout.WEST);
    panel.add( 
        new FeelPanel(SwingConstants.HORIZONTAL),
        BorderLayout.NORTH);
    frame.pack();
    frame.setVisible(true);
  }
}
package swingExamples;

import java.awt.Component;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

/**
 * A class to provide support for changing look and feel.
 *
 * @author Bryan Higgs
 * @version 1.0
 */
public abstract class LookAndFeel
{
  public static final String METAL   = "Metal",
                             SYSTEM  = "System",
                             MOTIF   = "Motif";
  
  /**
   * Changes look and feel and changes it dynamically for 
   * the component tree starting at component.
   */
  public static void setLookAndFeel(String feel, 
                                    Component component)
  {
    if (feel != null)
    {
      if (feel.equals(METAL))
      {
        feel = UIManager.getCrossPlatformLookAndFeelClassName();
      }
      else if (feel.equals(SYSTEM))
      {
        feel = UIManager.getSystemLookAndFeelClassName();
      }
      else if (feel.equals(MOTIF))
      {
        feel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
      }
      else
      {
        System.err.println(
            "Unexpected value of look and feel specified: "
            + feel);
        feel = UIManager.getCrossPlatformLookAndFeelClassName();
      }
      
      try
      {
        UIManager.setLookAndFeel(feel);
        SwingUtilities.updateComponentTreeUI(component);
      }
      catch (ClassNotFoundException e)
      {
        System.err.println(
            "Couldn't find class for specified look and feel:"
            + feel);
        System.err.println(
            "Did you include the L&F library in the class path?");
        System.err.println("Using the default look and feel.");
      }
      catch (UnsupportedLookAndFeelException e)
      {
        System.err.println(
            "Can't use the specified look and feel ("
            + feel + ") on this platform.");
        System.err.println("Using the default look and feel.");
      }
      catch (Exception e)
      {
        System.err.println(
            "Couldn't get specified look and feel ("
            + feel + "), for some reason.");
        System.err.println("Using the default look and feel.");
        e.printStackTrace();
      }
    }
  }
}
package swingExamples;

import java.awt.Toolkit;
import java.io.BufferedInputStream;
import java.io.IOException;
import javax.swing.ImageIcon;

/**
 * A class to provide utility methods for dealing
 * with images and icons.
 *
 * @author Bryan Higgs
 * @version 1.0
 */
public abstract class ImageUtilities
{
  /**
   * Returns an ImageIcon, or null if the path was invalid
   * When running  using Java Plug-in, getResourceAsStream
   * is more efficient than getResource
   */
  protected static ImageIcon createImageIcon(
                                Class baseClass, String path)
  {
    int MAX_IMAGE_SIZE = 124000;
            // Change this to the size of
            // the largest image, in bytes
    int count = 0;
    BufferedInputStream imgStream = new BufferedInputStream(
        baseClass.getResourceAsStream(path));
    if (imgStream != null)
    {
      byte buf[] = new byte[MAX_IMAGE_SIZE];
      try
      {
        count = imgStream.read(buf);
      }
      catch (IOException ieo)
      {
        System.err.println(
            "Couldn't read stream from file: " + path);
      }
      
      try
      {
        imgStream.close();
      }
      catch (IOException ieo)
      {
        System.err.println("Can't close file " + path);
      }
      
      if (count <= 0)
      {
        System.err.println("Empty file: " + path);
        return null;
      }
      return new ImageIcon(
          Toolkit.getDefaultToolkit().createImage(buf));
    }
    else
    {
      System.err.println("Couldn't find file: " + path);
      return null;
    }
  }
}

which produces something that, on my Microsoft XP system, looks like this:

and if you click on the Look and Feel radio buttons, you'll see changes like:

or:

As you set or unset the appropriate checkboxes and radio buttons, the slider changes its visual appearance.

If you want to try this out in real time, try clicking on the following launch button:

(You must have Java Web Start 1.5 or later installed on your system -- that should be the default for most Java installations.)

Note: Be patient when changing Look and Feel in this application.  On occasion, I have found the System look and feel to be rather sluggish the first time it's selected.

 

This page was last modified on 02 October, 2007