Skip to content

Instantly share code, notes, and snippets.

@RustyKnight
Created July 26, 2018 11:12
Show Gist options
  • Save RustyKnight/b93b085b5e43f26b7e96c07dd9589662 to your computer and use it in GitHub Desktop.
Save RustyKnight/b93b085b5e43f26b7e96c07dd9589662 to your computer and use it in GitHub Desktop.
An implementation of circular progress bar concept in Java/Swing using the 2D Graphics, Shapes API
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.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CircleProgressTest {
public static void main(String[] args) {
new CircleProgressTest();
}
public CircleProgressTest() {
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 {
private double progress = 0d;
private double radius = 90;
private CircleProgress cp;
public TestPane() {
cp = new CircleProgress(radius, 20, 0d);
Timer timer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (progress >= 1.0) {
((Timer) (e.getSource())).stop();
progress = 1.0;
} else {
progress += 0.001;
}
cp = new CircleProgress(radius, 20, progress);
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
double x = (getWidth() - (radius * 2d)) / 2d;
double y = (getHeight() - (radius * 2d)) / 2d;
g2d.transform(AffineTransform.getTranslateInstance(x, y));
g2d.setStroke(new BasicStroke(4f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2d.setColor(Color.DARK_GRAY);
g2d.draw(cp);
g2d.setColor(new Color(0, 161, 155));
g2d.fill(cp);
g2d.dispose();
}
}
}
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
public class CircleProgress extends Path2D.Double {
private double radius;
private double thickness; // subtracted from radius
private double progress;
public CircleProgress(double radius, double thickness, double progress) {
this.radius = radius;
this.thickness = thickness;
this.progress = progress;
build();
}
protected void build() {
double innerRadius = radius - thickness;
if (progress >= 1.0) {
Area outter = new Area(new Ellipse2D.Double(0, 0, radius * 2d, radius * 2d));
Area inner = new Area(new Ellipse2D.Double(thickness, thickness, innerRadius * 2d, innerRadius * 2d));
outter.subtract(inner);
append(outter, true);
} else if (progress <= 0.0) {
// What does this actually mean...?
} else {
double extent = -(360.0 * progress);
double startAt = 90d;
append(new Arc2D.Double(0, 0, radius * 2d, radius * 2d, startAt, extent, Arc2D.OPEN), true);
append(new Arc2D.Double(thickness, thickness, innerRadius * 2d, innerRadius * 2d, startAt + extent, -extent, Arc2D.OPEN), true);
closePath();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment