Google Tag Manager

2014/06/02

How to create a circular progress component

Code

class ProgressCircleUI extends BasicProgressBarUI {
  @Override public Dimension getPreferredSize(JComponent c) {
    Dimension d = super.getPreferredSize(c);
    int v = Math.max(d.width, d.height);
    d.setSize(v, v);
    return d;
  }
  @Override public void paint(Graphics g, JComponent c) {
    Insets b = progressBar.getInsets(); // area for border
    int barRectWidth  = progressBar.getWidth()  - b.right - b.left;
    int barRectHeight = progressBar.getHeight() - b.top - b.bottom;
    if (barRectWidth <= 0 || barRectHeight <= 0) {
      return;
    }

    // draw the cells
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(progressBar.getForeground());
    double degree = 360 * progressBar.getPercentComplete();
    double sz = Math.min(barRectWidth, barRectHeight);
    double cx = b.left + barRectWidth  * .5;
    double cy = b.top  + barRectHeight * .5;
    double or = sz * .5;
    double ir = or * .5; //or - 20;
    Shape inner = new Ellipse2D.Double(cx - ir, cy - ir, ir * 2, ir * 2);
    Shape outer = new Arc2D.Double(
        cx - or, cy - or, sz, sz, 90 - degree, degree, Arc2D.PIE);
    Area area = new Area(outer);
    area.subtract(new Area(inner));
    g2.fill(area);
    g2.dispose();

    // Deal with possible text painting
    if (progressBar.isStringPainted()) {
      paintString(g, b.left, b.top, barRectWidth, barRectHeight, 0, b);
    }
  }
}
import java.awt.*;
import javax.swing.*;

public class CircularProgressTest {
  public JComponent makeUI() {
    JProgressBar progress = new JProgressBar();
    // use JProgressBar#setUI(...) method
    progress.setUI(new ProgressCircleUI());
    progress.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
    progress.setStringPainted(true);
    progress.setFont(progress.getFont().deriveFont(24f));
    progress.setForeground(Color.ORANGE);

    (new Timer(50, e -> {
      int iv = Math.min(100, progress.getValue() + 1);
      progress.setValue(iv);
    })).start();

    JPanel p = new JPanel();
    p.add(progress);
    return p;
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new CircularProgressTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

References

8 comments:

  1. can you show how can i use this with a jframe?

    ReplyDelete
  2. How to run the file named MainPanel.java given in the src.zip file?
    Its gives error as Error: Could not find or load main class MainPanel.

    ReplyDelete
    Replies
    1. Hi Maheshwari,
      You may need to to call java -cp . example.MainPanel from the parent directionry of example.
      reference: Java error Could not find or load main class package - Stack Overflow

      Delete
  3. How do i change the color of the 64% label inside the blue circular progress bar. I just want to change the color of the text (64%). Thanks.

    ReplyDelete
    Replies
    1. You might be able to use UIManager.put("ProgressBar.selectionBackground", Color.ORANGE); or override the BasicProgressBarUI#getSelectionBackground() method:

      // ...
      // Deal with possible text painting
      if (progressBar.isStringPainted()) {
      paintString(g, b.left, b.top, barRectWidth, barRectHeight, 0, b);
      }
      }

      @Override protected Color getSelectionBackground() {
      return Color.RED;
      }

      Delete