4

Is there an easy way to change the value displayed in the label above a JSlider while using certain "look and feel"s?

To be clear, I'm talking about this value:

enter image description here

Specifically, I would like to show the value divided by 1000 instead of the value itself.

I know I can set labels for the tick if I display them, but then the user would have to guess the actual value.

I also know that I could remove the label using this answer, and then implement my own label that updates with the slider, but that is precisely what I am trying to avoid.

This really seems like an obvious issue considering JSlider does not support doubles.

Community
  • 1
  • 1
Vaelus
  • 1,065
  • 10
  • 27

1 Answers1

5

Specifically, I would like to show the value divided by 1000 instead of the value itself.

This might work: label.setText(String.format("%.3f", slider.getValue() / 1000f));

enter image description here

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public final class SliderTooltipTest {
  private JComponent makeUI() {
    JSlider slider = new JSlider(1, 100000) {
      private SliderPopupListener popupHandler;
      @Override public void updateUI() {
        removeMouseMotionListener(popupHandler);
        removeMouseListener(popupHandler);
        removeMouseWheelListener(popupHandler);
        super.updateUI();
        popupHandler = new SliderPopupListener();
        addMouseMotionListener(popupHandler);
        addMouseListener(popupHandler);
        addMouseWheelListener(popupHandler);
      }
    };
    slider.setMajorTickSpacing(10000);
    slider.setPaintTicks(true);

    JPanel p = new JPanel();
    p.setBorder(BorderFactory.createEmptyBorder(50, 10, 50, 10));
    p.add(new JLabel("1"));
    p.add(slider);
    p.add(new JLabel("100Gb/s"));
    return p;
  }
  public static void main(String... args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    try {
      for (UIManager.LookAndFeelInfo laf: UIManager.getInstalledLookAndFeels()) {
        if ("Nimbus".equals(laf.getName())) {
          UIManager.setLookAndFeel(laf.getClassName());
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new SliderTooltipTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}

class SliderPopupListener extends MouseAdapter {
  private final JWindow toolTip = new JWindow();
  private final JLabel label = new JLabel("", SwingConstants.CENTER);
  private final Dimension size = new Dimension(60, 20);
  private int prevValue = -1;

  public SliderPopupListener() {
    super();
    label.setOpaque(false);
    label.setBackground(UIManager.getColor("ToolTip.background"));
    //label.setBorder(UIManager.getBorder("ToolTip.border"));
    label.setBorder(BorderFactory.createLineBorder(Color.CYAN.darker()));
    toolTip.add(label);
    toolTip.setSize(size);
  }
  protected void updateToolTip(MouseEvent me) {
    JSlider slider = (JSlider) me.getComponent();
    int intValue = (int) slider.getValue();
    if (prevValue != intValue) {
      label.setText(String.format("%.3f", slider.getValue() / 1000f));
      Point pt = me.getPoint();
      pt.y = -size.height;
      SwingUtilities.convertPointToScreen(pt, me.getComponent());
      pt.translate(-size.width / 2, 0);
      toolTip.setLocation(pt);
    }
    prevValue = intValue;
  }
  @Override public void mouseDragged(MouseEvent me) {
    toolTip.setVisible(true);
    updateToolTip(me);
  }
  @Override public void mouseReleased(MouseEvent me) {
    toolTip.setVisible(false);
  }
}
aterai
  • 9,658
  • 4
  • 35
  • 44
  • This doesn't directly answer my question, but it seems like an acceptable alternative to what I was asking for if you add that what I originally wanted is not possible. – Vaelus Oct 31 '15 at 21:30