---
category: swing
folder: RotatingAnimationToggleIcon
title: JToggleButtonに回転アニメーション付き展開・折り畳みIconを設定する
title-en: Set an expand/collapse icon with rotating animation on a JToggleButton
tags: [JToggleButton, Icon, Animation, Timer]
author: aterai
pubdate: 2026-01-05T02:27:43+09:00
description: JToggleButtonに選択するとアニメーション効果付きで時計回りに90度回転、選択解除で-90度回転して元の0度に戻る展開・折り畳みIconを設定します。
summary-jp: JToggleButtonに選択するとアニメーション効果付きで時計回りに90度回転、選択解除で-90度回転して元の0度に戻る展開・折り畳みIconを設定します。
summary-en: Set the expand/collapse icon for the JToggleButton to rotate 90 degrees clockwise with an animation effect when selected, and rotate -90 degrees and return to the original 0 degree angle when deselected.
image: https://drive.google.com/uc?id=1_dqsxcmsL65a7BF3Tgtv50kcoFZOI0cz
---
* Summary [#summary]
JToggleButtonに選択するとアニメーション効果付きで時計回りに90度回転、選択解除で-90度回転して元の0度に戻る展開・折り畳みIconを設定します。
// #en{{Set the expand/collapse icon for the JToggleButton to rotate 90 degrees clockwise with an animation effect when selected, and rotate -90 degrees and return to the original 0 degree angle when deselected.}}
`JToggleButton`に選択するとアニメーション効果付きで時計回りに`90`度回転、選択解除で`-90`度回転して元の`0`度に戻る展開・折り畳み`Icon`を設定します。
// #en{{Set the expand/collapse icon for the `JToggleButton` to rotate 90 degrees clockwise with an animation effect when selected, and rotate -90 degrees and return to the original 0 degree angle when deselected.}}

#download(https://drive.google.com/uc?id=1_dqsxcmsL65a7BF3Tgtv50kcoFZOI0cz)

* Source Code Examples [#sourcecode]
#code(link){{
class AnimatableIcon implements Icon {
  private final Icon icon;
  private final Timer timer = new Timer(15, null);
  private double currentAngle;
  private double targetAngle;
  private Component parent;

  protected AnimatableIcon(Icon icon, Component parent) {
    this.icon = icon;
    this.parent = parent;
    double step = .5;
    this.timer.addActionListener(e -> {
      double diff = targetAngle - currentAngle;
      if (Math.abs(diff) < step) {
        currentAngle = targetAngle;
        timer.stop();
      } else {
        currentAngle += diff * step;
      }
      Optional.ofNullable(this.parent).ifPresent(Component::repaint);
    });
  }

  public void animateTo(double angle) {
    this.targetAngle = angle;
    if (!timer.isRunning()) {
      timer.start();
    }
  }

  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    if (this.parent == null) {
      this.parent = c;
    }
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    int cx = x + icon.getIconWidth() / 2;
    int cy = y + icon.getIconHeight() / 2;
    g2.rotate(Math.toRadians(currentAngle), cx, cy);
    icon.paintIcon(c, g2, x, y);
    g2.dispose();
  }

  @Override public int getIconWidth() {
    return icon.getIconWidth();
  }

  @Override public int getIconHeight() {
    return icon.getIconHeight();
  }
}
}}

* Description [#description]
- 折り畳み状態の右矢印アイコンは`Menu.arrowIcon`を使用
- アコーディオンパネルは[[JPanelをアコーディオン風に展開>Swing/AccordionPanel]]のタイトル部分を`JLabel`から`BoxLayout`を設定した`JButton`に変更して使用
-- `JButton`の子要素として左端にタイトル文字列表示用の`JLabel`、右端に展開・折り畳み`Icon`を設定した`JToggleButton`を配置
- `JButton`、またはその子要素の`JToggleButton`がクリックされたらアコーディオンパネルの展開・折り畳みと合わせて展開・折り畳み`Icon`の回転角度を設定してアニメーションを開始
-- 回転アニメーション用の`Timer`は各`Icon`毎に作成して使用
--- [[Timerの使用数を変更>Swing/TimerAction]]

#code{{
private void rotate(AnimatableIcon animeIcon) {
  if (toggleButton.isSelected()) {
    animeIcon.animateTo(90d);
    panel.setVisible(true);
  } else {
    animeIcon.animateTo(0d);
    panel.setVisible(false);
  }
  revalidate();
  EventQueue.invokeLater(() -> panel.scrollRectToVisible(panel.getBounds()));
}
}}

* Reference [#reference]
- [[JPanelをアコーディオン風に展開>Swing/AccordionPanel]]
- [[Timerの使用数を変更>Swing/TimerAction]]

* Comment [#comment]
#comment
#comment