Creating a Progress Dial
Articles —> Creating a Progress Dial
A program or web application often requires the need to indicate the progress of a background process to a user. A flashy way to go about indicating progress is via some type of animation, popular choice is the progress dial - similar to a clock, the bars (or hour-hands) of the clock light up as as things progress.
Hide ▼
Having the need to customize progress dials in different context (size, color, and presentation media) - I decided a flexible method would be to create my own program to generate the progress dials. From there, I can incorporate the progress dials directly into an application (java based), or save the results as images to piece together into an animated gif image. The code itself is quite straightforward - albeit containing poorly designed hard-coded values together with a bit of cryptic syntax. The code relies on rotation of several rounded rects to correctly place them, with their colors defined by the position of the current 'time':
import java.awt.Color; import java.awt.Dimension; 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.SwingUtilities; import javax.swing.Timer; /** * Progress Dial * @author Greg Cope * */ public class Progress extends JPanel { private static final long serialVersionUID = 4321421L; int barCount = 12; int current = 0;//current activated bar private javax.swing.Timer timer = null;//animating timer /** * Constructor that automatically creates a timer to animate the progress bar */ public Progress(){ setBackground(Color.WHITE); setOpaque(true); timer = new Timer(60, new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { current++; if ( current > barCount - 1){ current = 0; } repaint(); } }); timer.start(); } @Override public void paintComponent(Graphics gr){ Graphics2D g = (Graphics2D)gr; super.paintComponent(g); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int width = getWidth() > getHeight() ? getWidth() : getHeight();//get the shortest dimensions int padding = (int)(width * 0.20d); AffineTransform at = new AffineTransform(g.getTransform()); int center = width/2; int innerRadius = 10; int barHeight = 10; //get indexes for coloring the bars neighboring current int prev = current - 1 < 0 ? barCount - 1 : current - 1; int prevPrev = current - 2 >= 0 ? current - 2 : (current - 2 == -1 ? barCount - 1 : barCount - 2) ; for ( int i = 0; i < barCount; i++ ){ double degrees = (i * 360d / barCount); g.setTransform(at); g.translate(center - innerRadius, center); g.rotate(Math.toRadians(degrees)); //cryptic syntax below for brevity int opacity = i == current ? 255 : (i == prev ? 175 : (i == prevPrev ? 125 : 50)); g.setColor(new Color(0,0,0,opacity)); g.fillRoundRect(2*innerRadius,-barHeight/2, width / 2 - padding, barHeight, 10, 10); } } public static void main(String[] args) throws Exception{ SwingUtilities.invokeAndWait(new Runnable(){ @Override public void run() { Progress p = new Progress(); JFrame frame = new JFrame(); p.setPreferredSize(new Dimension(200,200)); frame.add(p); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } }
The nice thing about this code: just about any animated gif (see one above created using this exact code) can be constructed by saving every 'frame' as an image, and then stitching those images together as a gif in image processing software (rather than stitch together as a gif with java, I prefer image editing software for to allow for dithering in order to maintain the anti-alias affects).
Comments
- singh Peo - July, 12, 2020
thank for work :D