Painting the slider icon of JSlider
There are three ways:
- change Java Look and Feel,
Preferred of Ways
- OverRide XxxSliderUI, but that would be Look and Feel sensitive, and not easy way
- learning The Synth Look and Feel
Example using Synth
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>
Extending the BasicSliderUI
delegate is not without peril, but it does allow arbitrary control over the rendering, as suggested in the example below.
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);
}
}
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:
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:
// ... 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);