Painting the slider icon of JSlider
Asked Answered
W

3

9

Would like to repaint the the marker or the thumb of the JSlider instead of the standard gray. How can I achieve this?

Whorled answered 9/8, 2011 at 7:16 Comment(0)
T
9

There are three ways:

  1. change Java Look and Feel, Preferred of Ways
  2. OverRide XxxSliderUI, but that would be Look and Feel sensitive, and not easy way
  3. learning The Synth Look and Feel

Example using Synth

Synth slider

SynthSliderTest.java

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

public class SynthSliderTest {

    private JFrame f = new JFrame();

    public SynthSliderTest() {
        try {
            SynthLookAndFeel laf = new SynthLookAndFeel();
            laf.load(SynthSliderTest.class.getResourceAsStream("yourPathTo/demo.xml"), SynthSliderTest.class);
            UIManager.setLookAndFeel(laf);
        } catch (Exception e) {
            e.printStackTrace();
        }
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(makeUI());
        f.setSize(320, 240);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public JComponent makeUI() {
        JSlider slider = new JSlider(0, 100);
        JPanel p = new JPanel();
        p.add(slider);
        return p;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                SynthSliderTest synthSliderTest = new SynthSliderTest();
            }
        });
    }
}

demo.xml file

<?xml version="1.0" encoding="UTF-8"?>

<synth>
    <style id="backingStyle">
        <opaque value="TRUE"/>
        <font name="Dialog" size="12"/>
        <state>
            <color value="WHITE" type="BACKGROUND"/>
            <color value="BLACK" type="FOREGROUND"/>
        </state>
    </style>
    <bind style="backingStyle" type="region" key=".*"/>

    <style id="SliderTrackStyle">
        <opaque value="TRUE"/>
        <state>
            <color type="BACKGROUND" value="ORANGE"/>
        </state>
    </style>
    <bind style="SliderTrackStyle" type="region" key="SliderTrack" />

    <style id="SliderThumbStyle">
        <opaque value="TRUE"/>
        <state>
            <color type="BACKGROUND" value="RED"/>
        </state>
        <state value="PRESSED">
            <color type="BACKGROUND" value="GREEN"/>
        </state>
    <!-- state value="MOUSE_OVER">
      <color type="BACKGROUND" value="BLUE"/>
    </state -->
    </style>
    <bind style="SliderThumbStyle" type="region" key="SliderThumb" />
</synth>
Treviso answered 9/8, 2011 at 7:33 Comment(0)
D
19

Extending the BasicSliderUI delegate is not without peril, but it does allow arbitrary control over the rendering, as suggested in the example below.

BasicSliderUI subclass image

slider.setUI(new MySliderUI(slider));
...
private static class MySliderUI extends BasicSliderUI {

    private static float[] fracs = {0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f};
    private LinearGradientPaint p;

    public MySliderUI(JSlider slider) {
        super(slider);
    }

    @Override
    public void paintTrack(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        Rectangle t = trackRect;
        Point2D start = new Point2D.Float(t.x, t.y);
        Point2D end = new Point2D.Float(t.width, t.height);
        Color[] colors = {Color.magenta, Color.blue, Color.cyan,
            Color.green, Color.yellow, Color.red};
        p = new LinearGradientPaint(start, end, fracs, colors);
        g2d.setPaint(p);
        g2d.fillRect(t.x, t.y, t.width, t.height);
    }

    @Override
    public void paintThumb(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        Rectangle t = thumbRect;
        g2d.setColor(Color.black);
        int tw2 = t.width / 2;
        g2d.drawLine(t.x, t.y, t.x + t.width - 1, t.y);
        g2d.drawLine(t.x, t.y, t.x + tw2, t.y + t.height);
        g2d.drawLine(t.x + t.width - 1, t.y, t.x + tw2, t.y + t.height);
    }
}
Dayledaylight answered 9/8, 2011 at 12:36 Comment(2)
I used this code but found I needed it to handle being disabled, so I added this code to lower the saturation of the color bar: if (!this.slider.isEnabled()) for (int i=0 ; i<colors.length ; i++) { float[] hsv = Color.RGBtoHSB(colors[i].getRed(),colors[i].getGreen(),colors[i].getBlue(),null); colors[i] = new Color(Color.HSBtoRGB(hsv[0], 0.25f, hsv[2])); }Koh
Amazingly powerful and simply presented! Thank you!Commingle
T
9

There are three ways:

  1. change Java Look and Feel, Preferred of Ways
  2. OverRide XxxSliderUI, but that would be Look and Feel sensitive, and not easy way
  3. learning The Synth Look and Feel

Example using Synth

Synth slider

SynthSliderTest.java

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

public class SynthSliderTest {

    private JFrame f = new JFrame();

    public SynthSliderTest() {
        try {
            SynthLookAndFeel laf = new SynthLookAndFeel();
            laf.load(SynthSliderTest.class.getResourceAsStream("yourPathTo/demo.xml"), SynthSliderTest.class);
            UIManager.setLookAndFeel(laf);
        } catch (Exception e) {
            e.printStackTrace();
        }
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(makeUI());
        f.setSize(320, 240);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public JComponent makeUI() {
        JSlider slider = new JSlider(0, 100);
        JPanel p = new JPanel();
        p.add(slider);
        return p;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                SynthSliderTest synthSliderTest = new SynthSliderTest();
            }
        });
    }
}

demo.xml file

<?xml version="1.0" encoding="UTF-8"?>

<synth>
    <style id="backingStyle">
        <opaque value="TRUE"/>
        <font name="Dialog" size="12"/>
        <state>
            <color value="WHITE" type="BACKGROUND"/>
            <color value="BLACK" type="FOREGROUND"/>
        </state>
    </style>
    <bind style="backingStyle" type="region" key=".*"/>

    <style id="SliderTrackStyle">
        <opaque value="TRUE"/>
        <state>
            <color type="BACKGROUND" value="ORANGE"/>
        </state>
    </style>
    <bind style="SliderTrackStyle" type="region" key="SliderTrack" />

    <style id="SliderThumbStyle">
        <opaque value="TRUE"/>
        <state>
            <color type="BACKGROUND" value="RED"/>
        </state>
        <state value="PRESSED">
            <color type="BACKGROUND" value="GREEN"/>
        </state>
    <!-- state value="MOUSE_OVER">
      <color type="BACKGROUND" value="BLUE"/>
    </state -->
    </style>
    <bind style="SliderThumbStyle" type="region" key="SliderThumb" />
</synth>
Treviso answered 9/8, 2011 at 7:33 Comment(0)
C
2

Expanding on TrashGod's very helpful answer, I added in a few lines of code to allow the bar to be filled up to the point in which you have moved it. The rest of the bar will be blank:

enter image description here

The code to do this is:

@Override
public void paintTrack(Graphics g) {

    // ... TrashGod's code ...

    // calculate how much of the progress bar to fill
    double percentage = (double)slider.getValue()/(double)slider.getMaximum();

    // fill the progress bar with a rectange of that size, (with curved corners of 4px diameter)
    g2d.fillRoundRect(t.x, t.y, (int)(t.width*percentage), t.height, 4, 4);

    // ...

}

And if you want a background color as well, paint a second rectange before you paint the first:

enter image description here

    // ... TrashGod's code ...

    // calculate how much of the progress bar to fill
    double percentage = (double)slider.getValue()/(double)slider.getMaximum();

    // PAINT THE BACKGROUND
    // create a gradient paint for the background
    p = new LinearGradientPaint(start, end, new float[] {0.4f,0.8f}, new Color[] {Color.gray.brighter(), Color.gray.brighter().brighter()});
    g2d.setPaint(p);
    g2d.fillRoundRect((int)(t.width*percentage), t.y, t.width - (int)(t.width*percentage), t.height, 4, 4);

    // PAINT THE FOREGROUND
    // create the gradient paint
    p = new LinearGradientPaint(start, end, fracs, colors);
    g2d.setPaint(p);

    // fill the progress bar with a rectange of that size, (with curved corners of 4px diameter)
    g2d.fillRoundRect(t.x, t.y, (int)(t.width*percentage), t.height, 4, 4);
Commingle answered 14/4, 2019 at 0:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.