Как заполнить jslider track до точки текущего значения thumb с помощью Nimubs L&F?


Я работаю над слайдером громкости и хотел бы изменить внешний вид Nimbus по умолчанию JSlider.

Я хочу, чтобы мой JSlider автоматически заполнял дорожку до точки текущего значения пальца. Идея такого подхода была бы такой (см. Рисунок)

Второй jSlider заполняет свой фон до значения точки большого пальца.

Я пытался расширить BasicSliderUI и переопределить метод paintTrack(), но безуспешно. Я также попытался снять кожу с JSlider (см. Пример http://www.jasperpotts.com/blog/2008/08/skinning-a-slider-with-nimbus/) но это похоже, что этот метод только меняет внешний вид JSlider.

Кто-нибудь знает, как подойти к этой проблеме?

1 2

1 ответ:

Этот пример поддерживается только для горизонтальных JSlider:

Введите описание изображения здесь

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

public class SliderSkinDemo2 {
  public JComponent makeUI() {
    UIDefaults d = new UIDefaults();
    d.put("Slider:SliderTrack[Enabled].backgroundPainter", new Painter<JSlider>() {
      @Override public void paint(Graphics2D g, JSlider c, int w, int h) {
        int arc         = 10;
        int trackHeight = 8;
        int trackWidth  = w - 2;
        int fillTop     = 4;
        int fillLeft    = 1;

        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                           RenderingHints.VALUE_ANTIALIAS_ON);
        g.setStroke(new BasicStroke(1.5f));
        g.setColor(Color.GRAY);
        g.fillRoundRect(fillLeft, fillTop, trackWidth, trackHeight, arc, arc);

        int fillBottom = fillTop + trackHeight;
        int fillRight  = xPositionForValue(
            c.getValue(), c,
            new Rectangle(fillLeft, fillTop, trackWidth, fillBottom - fillTop));

        g.setColor(Color.ORANGE);
        g.fillRect(fillLeft + 1, fillTop + 1, fillRight - fillLeft, fillBottom - fillTop);

        g.setColor(Color.WHITE);
        g.drawRoundRect(fillLeft, fillTop, trackWidth, trackHeight, arc, arc);
      }
      //@see javax/swing/plaf/basic/BasicSliderUI#xPositionForValue(int value)
      protected int xPositionForValue(int value, JSlider slider, Rectangle trackRect) {
        int min = slider.getMinimum();
        int max = slider.getMaximum();
        int trackLength = trackRect.width;
        double valueRange = (double) max - (double) min;
        double pixelsPerValue = (double) trackLength / valueRange;
        int trackLeft = trackRect.x;
        int trackRight = trackRect.x + (trackRect.width - 1);
        int xPosition;

        xPosition = trackLeft;
        xPosition += Math.round(pixelsPerValue * ((double) value - min));

        xPosition = Math.max(trackLeft, xPosition);
        xPosition = Math.min(trackRight, xPosition);

        return xPosition;
      }
    });

    JSlider slider = new JSlider();
    slider.putClientProperty("Nimbus.Overrides", d);

    JPanel p = new JPanel();
    p.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
    p.setBackground(Color.DARK_GRAY);
    p.add(new JSlider());
    p.add(Box.createRigidArea(new Dimension(200, 20)));
    p.add(slider);
    return p;
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      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 SliderSkinDemo2().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}