How to customize a JProgressBar?
I am making a launcher and I want to have a customized ProgressBar. I have done some research and it's possible with JavaFX(Never did something with it) and it's possible with replacing the UI. I am looking for a bar with rounded edges and a rounded fill. Something like this:
package gui;
import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
public class Gui extends JFrame {
private static final long serialVersionUID = 1L;
private final JPanel contentPane;
final JFrame frame = new JFrame();
int pX,pY;
/**
* Launch the application.
*/
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
final Gui frame = new Gui();
frame.setVisible(true);
} catch (final Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Gui() {
this.setTitle("Exile Launcher");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(0, 0, 1000, 563);
this.contentPane = new JPanel();
this.contentPane.setBorder(null);
this.setContentPane(this.contentPane);
this.contentPane.setLayout(null);
this.setUndecorated(true);
this.setLocation(Toolkit.getDefaultToolkit().getScreenSize().width/2-this.getSize().width/2, Toolkit.getDefaultToolkit().getScreenSize().height/2-this.getSize().height/2);
int X = 24;
int Y = 40;
final JButton HomeButton = new JButton();
HomeButton.setFocusPainted(false);
HomeButton.setBorder(null);
HomeButton.setContentAreaFilled(false);
HomeButton.setIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/0.png")));
HomeButton.setRolloverIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/0_h.png")));
HomeButton.setBounds(new Rectangle(X, Y, 50, 50));
this.contentPane.add(HomeButton);
HomeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
try {
Desktop.getDesktop().browse(new URL("http://www.google.nl").toURI());
} catch (IOException | URISyntaxException e1) {
e1.printStackTrace();
}
}
});
Y += 60;
final JButton ForumButton = new JButton();
ForumButton.setFocusPainted(false);
ForumButton.setBorder(null);
ForumButton.setContentAreaFilled(false);
ForumButton.setIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/1.png")));
ForumButton.setRolloverIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/1_h.png")));
ForumButton.setBounds(new Rectangle(X, Y, 50, 50));
this.contentPane.add(ForumButton);
Y += 60;
final JButton VoteButton = new JButton();
VoteButton.setFocusPainted(false);
VoteButton.setBorder(null);
VoteButton.setContentAreaFilled(false);
VoteButton.setIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/4.png")));
VoteButton.setRolloverIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/4_h.png")));
VoteButton.setBounds(new Rectangle(X, Y, 50, 50));
this.contentPane.add(VoteButton);
final JButton CloseButton = new JButton();
CloseButton.setFocusPainted(false);
CloseButton.setBorder(null);
CloseButton.setContentAreaFilled(false);
CloseButton.setIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/Close.png")));
CloseButton.setRolloverIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/Close_h.png")));
CloseButton.setBounds(new Rectangle(875, 0, 27, 28));
this.contentPane.add(CloseButton);
CloseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
System.exit(0);
}
});
final JButton MinimizeButton = new JButton();
MinimizeButton.setFocusPainted(false);
MinimizeButton.setBorder(null);
MinimizeButton.setContentAreaFilled(false);
MinimizeButton.setIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/Minimize.png")));
MinimizeButton.setRolloverIcon(new ImageIcon(this.getClass().getClassLoader().getResource("Images/Minimize_h.png")));
MinimizeButton.setBounds(new Rectangle(850, -1, 27, 28));
this.contentPane.add(MinimizeButton);
MinimizeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
setState(Frame.ICONIFIED);
}
});
final JProgressBar ProgressBar = new JProgressBar();
ProgressBar.setLocation(150, 500);
ProgressBar.setSize(600, 50);
ProgressBar.setValue(50);
getContentPane().add(ProgressBar);
final JLabel backgroundLabel = new JLabel(new ImageIcon(this.getClass().getClassLoader().getResource("Images/Background.png")));
backgroundLabel.setBounds(new Rectangle(0, 0, 1000, 563));
getContentPane().add(backgroundLabel);
JPanel titleBar = new JPanel();
titleBar.setBounds(0, 0, 1000, 25);
contentPane.add(titleBar);
titleBar.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent me)
{
// Get x,y and store them
pX=me.getX();
pY=me.getY();
}
});
titleBar.addMouseMotionListener(new MouseAdapter(){
public void mouseDragged(MouseEvent me)
{
setLocation(getLocation().x+me.getX()-pX,getLocation().y+me.getY()-pY);
}
});
}
}
There are a number of ways you might achieve this, one of the better ways would be to create a custom ProgressBarUI
delegate which paints itself the way you want, for example...
public class FancyProgressBar extends BasicProgressBarUI {
@Override
protected Dimension getPreferredInnerVertical() {
return new Dimension(20, 146);
}
@Override
protected Dimension getPreferredInnerHorizontal() {
return new Dimension(146, 20);
}
@Override
protected void paintDeterminate(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int iStrokWidth = 3;
g2d.setStroke(new BasicStroke(iStrokWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2d.setColor(progressBar.getBackground());
g2d.setBackground(progressBar.getBackground());
int width = progressBar.getWidth();
int height = progressBar.getHeight();
RoundRectangle2D outline = new RoundRectangle2D.Double((iStrokWidth / 2), (iStrokWidth / 2),
width - iStrokWidth, height - iStrokWidth,
height, height);
g2d.draw(outline);
int iInnerHeight = height - (iStrokWidth * 4);
int iInnerWidth = width - (iStrokWidth * 4);
double dProgress = progressBar.getPercentComplete();
if (dProgress < 0) {
dProgress = 0;
} else if (dProgress > 1) {
dProgress = 1;
}
iInnerWidth = (int) Math.round(iInnerWidth * dProgress);
int x = iStrokWidth * 2;
int y = iStrokWidth * 2;
Point2D start = new Point2D.Double(x, y);
Point2D end = new Point2D.Double(x, y + iInnerHeight);
float[] dist = {0.0f, 0.25f, 1.0f};
Color[] colors = {progressBar.getBackground(), progressBar.getBackground().brighter(), progressBar.getBackground().darker()};
LinearGradientPaint p = new LinearGradientPaint(start, end, dist, colors);
g2d.setPaint(p);
RoundRectangle2D fill = new RoundRectangle2D.Double(iStrokWidth * 2, iStrokWidth * 2,
iInnerWidth, iInnerHeight, iInnerHeight, iInnerHeight);
g2d.fill(fill);
g2d.dispose();
}
@Override
protected void paintIndeterminate(Graphics g, JComponent c) {
super.paintIndeterminate(g, c); //To change body of generated methods, choose Tools | Templates.
}
}
Normally you might be tempered to register this as the default look and feel delegate of all JProgressBar
s, but typically, I would install only on those instance of JProgressBar
you really wanted it, that comes down to you.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.LinearGradientPaint;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.basic.BasicProgressBarUI;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBackground(Color.BLACK);
JProgressBar fancyPB = new JProgressBar();
fancyPB.setUI(new FancyProgressBar());
JProgressBar normalPB = new JProgressBar();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(fancyPB, gbc);
add(normalPB, gbc);
Timer timer = new Timer(250, new ActionListener() {
private int count = 0;
@Override
public void actionPerformed(ActionEvent e) {
fancyPB.setValue(count);
normalPB.setValue(count);
count++;
if (count >= 100) {
((Timer)e.getSource()).stop();
}
}
});
timer.start();
}
}
public class FancyProgressBar extends BasicProgressBarUI {
@Override
protected Dimension getPreferredInnerVertical() {
return new Dimension(20, 146);
}
@Override
protected Dimension getPreferredInnerHorizontal() {
return new Dimension(146, 20);
}
@Override
protected void paintDeterminate(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int iStrokWidth = 3;
g2d.setStroke(new BasicStroke(iStrokWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2d.setColor(progressBar.getBackground());
g2d.setBackground(progressBar.getBackground());
int width = progressBar.getWidth();
int height = progressBar.getHeight();
RoundRectangle2D outline = new RoundRectangle2D.Double((iStrokWidth / 2), (iStrokWidth / 2),
width - iStrokWidth, height - iStrokWidth,
height, height);
g2d.draw(outline);
int iInnerHeight = height - (iStrokWidth * 4);
int iInnerWidth = width - (iStrokWidth * 4);
double dProgress = progressBar.getPercentComplete();
if (dProgress < 0) {
dProgress = 0;
} else if (dProgress > 1) {
dProgress = 1;
}
iInnerWidth = (int) Math.round(iInnerWidth * dProgress);
int x = iStrokWidth * 2;
int y = iStrokWidth * 2;
Point2D start = new Point2D.Double(x, y);
Point2D end = new Point2D.Double(x, y + iInnerHeight);
float[] dist = {0.0f, 0.25f, 1.0f};
Color[] colors = {progressBar.getBackground(), progressBar.getBackground().brighter(), progressBar.getBackground().darker()};
LinearGradientPaint p = new LinearGradientPaint(start, end, dist, colors);
g2d.setPaint(p);
RoundRectangle2D fill = new RoundRectangle2D.Double(iStrokWidth * 2, iStrokWidth * 2,
iInnerWidth, iInnerHeight, iInnerHeight, iInnerHeight);
g2d.fill(fill);
g2d.dispose();
}
@Override
protected void paintIndeterminate(Graphics g, JComponent c) {
super.paintIndeterminate(g, c); //To change body of generated methods, choose Tools | Templates.
}
}
}
If you want to install the look and feel delegate as the default delegate, take a look at this answer for more details (scroll down a little, it's there)