11

I'm wondering if any of you know how to display a nice looking progress bar in Java, mostly using Swing, although I don't mind using third-party libraries.

I've been looking at JProgressBar tutorials but none of them refer to styling the bar. Reading the API I found a getUI method that returns ProgressBarUI object but I don't see many ways to customize that one.

What I want is to add rounded corners, change background and foreground color, width, lenght, the usual.

Thanks!

mKorbel
  • 109,525
  • 20
  • 134
  • 319
AlejandroVK
  • 7,373
  • 13
  • 54
  • 77

2 Answers2

24

If you don't want to replace the user's chosen Look & Feel, you can just replace the UI delegate with one derived from BasicProgressBarUI.

enter image description here

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.plaf.basic.BasicProgressBarUI;

/** @see http://stackoverflow.com/questions/8884297 */
public class ProgressBarUITest extends JPanel {

    public ProgressBarUITest() {
        JProgressBar jpb = new JProgressBar();
        jpb.setUI(new MyProgressUI());
        jpb.setForeground(Color.blue);
        jpb.setIndeterminate(true);
        this.add(jpb);
    }

    private static class MyProgressUI extends BasicProgressBarUI {

        private Rectangle r = new Rectangle();

        @Override
        protected void paintIndeterminate(Graphics g, JComponent c) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
            r = getBox(r);
            g.setColor(progressBar.getForeground());
            g.fillOval(r.x, r.y, r.width, r.height);
        }
    }

    private void display() {
        JFrame f = new JFrame("ProgressBarUITest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

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

            @Override
            public void run() {
                new ProgressBarUITest().display();
            }
        });
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thanks for a very detailed answer! +1 and correct answer :D. In any case, at the end I did it using JPanel with rounded borders, overlapping one on top of another, since my "progress bars" are static, the trick does it. Thanks anyway for the nice tip, trashgod, will write it down for further reference – AlejandroVK Jan 17 '12 at 09:26
  • 1
    @Trashgod +1 for the snippet I found this while looking how to customize `JProgressBar` on Google :). 1 thing with the snippet: in `paintIndeterminate(..)` you cast `Graphic`s object `g` to `Graphics2D` however u paint via `g.fillOval(..)` thus missing the `g2d.fillOval(..)` call which would create the `JProgressBar` rectangular border. – David Kroukamp Nov 15 '12 at 10:43
  • @DavidKroukamp: Good catch; although the "legacy methods perform identically…under default attribute settings," `g2d.fill(shape)` is much more versatile. – trashgod Nov 15 '12 at 17:45
6

The easiest way to do that would be to change the LookAndFeel or maybe even create your own class that extends off of one of the default L&Fs and just changes the UI for the progress bar...

Feni
  • 303
  • 1
  • 4
  • Any ideas on how to do this specifically for a JProgressBar? – AlejandroVK Jan 16 '12 at 18:53
  • @AlejandroVK hard to tell you have to try http://stackoverflow.com/questions/3954616/look-and-feel-in-java, I'd preffer Substance, but is too much EDT sensitive, – mKorbel Jan 16 '12 at 19:03