---
category: swing
folder: ProgressCircle
title: JProgressBarの進捗状況を円形で表示する
tags: [JProgressBar, SwingWorker]
author: aterai
pubdate: 2014-06-02T00:02:59+09:00
description: JProgressBarの進捗状況を円形表示するように設定します。
image: https://lh3.googleusercontent.com/-K2Us5zyEGJs/U4rt4SgHxVI/AAAAAAAACGo/IBfgQ2C1jxE/s800/ProgressCircle.png
hreflang:
    href: https://java-swing-tips.blogspot.com/2014/06/how-to-create-circular-progress.html
    lang: en
---
* Summary [#summary]
`JProgressBar`の進捗状況を円形表示するように設定します。

#download(https://lh3.googleusercontent.com/-K2Us5zyEGJs/U4rt4SgHxVI/AAAAAAAACGo/IBfgQ2C1jxE/s800/ProgressCircle.png)

* Source Code Examples [#sourcecode]
#code(link){{
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) {
    Rectangle rect = SwingUtilities.calculateInnerArea(progressBar, null);
    if (rect.isEmpty()) {
      return;
    }

    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);

    Object o = progressBar.getClientProperty("Slider.clockwise");
    int dir = Objects.equals(o, Boolean.TRUE) ? -1 : 1;
    double start = 90d;
    double degree = dir * 360d * progressBar.getPercentComplete();
    double sz = Math.min(rect.width, rect.height);
    double cx = rect.getCenterX();
    double cy = rect.getCenterY();
    double or = sz * .5;
    double ir = or * .5; // .8;
    Shape inner = new Ellipse2D.Double(cx - ir, cy - ir, ir * 2d, ir * 2d);
    Shape outer = new Ellipse2D.Double(cx - or, cy - or, sz, sz);
    Shape sector = new Arc2D.Double(cx - or, cy - or, sz, sz, start, degree, Arc2D.PIE);

    Area foreground = new Area(sector);
    Area background = new Area(outer);
    Area hole = new Area(inner);

    foreground.subtract(hole);
    background.subtract(hole);

    // Draw the track
    g2.setPaint(new Color(0xDD_DD_DD));
    g2.fill(background);

    // Draw the circular sector
    g2.setPaint(progressBar.getForeground());
    g2.fill(foreground);
    g2.dispose();

    // Deal with possible text painting
    if (progressBar.isStringPainted()) {
      Insets ins = progressBar.getInsets();
      paintString(g, rect.x, rect.y, rect.width, rect.height, 0, ins);
    }
  }
}
}}

* Explanation [#explanation]
上記のサンプルでは、`BasicProgressBarUI#paint(Graphics g, JComponent c)`メソッドをオーバーライドして進捗状況を円形で表現する`ProgressBarUI`を作成し、これを`JProgressBar`に設定しています。

- 表示上、中心から表示枠矩形の上辺中央を結ぶ線が弧の始角で時計回り方向が増加を表すように`Arc2D`を作成
-- 反時計回りの増加に切り替える`JCheckBox`を追加
- 推奨サイズが常に正方形になるように、`BasicProgressBarUI#getPreferredSize(JComponent c)`メソッドをオーバーライドしているので、`JProgressBar`の方向設定(`SwingConstants.VERTICAL`,`SwingConstants.HORIZONTAL`)は無視している
- 不確定状態の描画は未対応
-- `BasicProgressBarUI#paintDeterminate(...)`,`BasicProgressBarUI#paintIndeterminate(...)`メソッドはオーバーライドしていない

* Reference [#reference]
- [[OverlayLayoutで複数のJButtonを重ねて複合ボタンを作成>Swing/CompoundButton]]
- [[JProgressBarにUIを設定してインジケータの色を変更>Swing/GradientPalletProgressBar]]
- [[JProgressBarの形状をドーナツ状の半円に変更してスピードメーターを作成する>Swing/SemicircleGauge]]

* Comment [#comment]
#comment
#comment