Swing/AnimeIcon のバックアップ(No.27)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/AnimeIcon へ行く。
- 1 (2007-03-26 (月) 00:29:10)
- 2 (2007-03-28 (水) 18:41:47)
- 3 (2007-04-10 (火) 15:45:54)
- 4 (2007-04-16 (月) 12:45:57)
- 5 (2007-04-17 (火) 18:27:40)
- 6 (2007-05-09 (水) 20:01:26)
- 7 (2007-07-11 (水) 23:49:44)
- 8 (2007-07-24 (火) 22:43:03)
- 9 (2007-07-25 (水) 01:39:27)
- 10 (2007-07-25 (水) 12:41:27)
- 11 (2009-11-26 (木) 15:53:44)
- 12 (2009-12-17 (木) 01:44:29)
- 13 (2009-12-17 (木) 11:07:18)
- 14 (2010-03-08 (月) 13:13:39)
- 15 (2010-12-12 (日) 23:20:10)
- 16 (2011-04-29 (金) 15:31:12)
- 17 (2013-03-13 (水) 15:39:14)
- 18 (2013-08-17 (土) 01:17:02)
- 19 (2013-08-17 (土) 05:01:00)
- 20 (2014-03-18 (火) 18:50:31)
- 21 (2015-01-20 (火) 15:44:29)
- 22 (2015-03-13 (金) 13:42:47)
- 23 (2016-05-26 (木) 14:28:17)
- 24 (2016-08-17 (水) 18:46:54)
- 25 (2017-03-29 (水) 19:36:44)
- 26 (2017-03-30 (木) 14:10:40)
- 27 (2017-10-18 (水) 13:38:25)
- 28 (2019-04-26 (金) 18:20:51)
- 29 (2019-05-11 (土) 15:55:26)
- 30 (2021-02-09 (火) 19:11:27)
- 31 (2024-02-02 (金) 11:37:11)
- category: swing folder: AnimeIcon title: Timerでアニメーションするアイコンを作成 tags: [Timer, Animation, Icon] author: aterai pubdate: 2006-03-13T00:29:10+09:00 description: javax.swing.Timerを使って、アニメーションするアイコンを作成します。 image:
概要
javax.swing.Timer
を使って、アニメーションするアイコンを作成します。
Screenshot
Advertisement
サンプルコード
class AnimatedLabel extends JLabel implements ActionListener {
private final Timer animator;
private final AnimeIcon icon = new AnimeIcon();
public AnimatedLabel() {
super();
animator = new Timer(100, this);
setIcon(icon);
addHierarchyListener(new HierarchyListener() {
@Override public void hierarchyChanged(HierarchyEvent e) {
if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0
&& !e.getComponent().isDisplayable()) {
stopAnimation();
}
}
});
}
@Override public void actionPerformed(ActionEvent e) {
icon.next();
repaint();
}
public void startAnimation() {
icon.setRunning(true);
animator.start();
}
public void stopAnimation() {
icon.setRunning(false);
animator.stop();
}
}
class AnimeIcon implements Icon, Serializable {
private static final long serialVersionUID = 1L;
private static final Color ELLIPSE_COLOR = new Color(.5f, .5f, .5f);
private static final double R = 2d;
private static final double SX = 1d;
private static final double SY = 1d;
private static final int WIDTH = (int) (R * 8 + SX * 2);
private static final int HEIGHT = (int) (R * 8 + SY * 2);
private final List<Shape> list = new ArrayList<Shape>(Arrays.asList(
new Ellipse2D.Double(SX + 3 * R, SY + 0 * R, 2 * R, 2 * R),
new Ellipse2D.Double(SX + 5 * R, SY + 1 * R, 2 * R, 2 * R),
new Ellipse2D.Double(SX + 6 * R, SY + 3 * R, 2 * R, 2 * R),
new Ellipse2D.Double(SX + 5 * R, SY + 5 * R, 2 * R, 2 * R),
new Ellipse2D.Double(SX + 3 * R, SY + 6 * R, 2 * R, 2 * R),
new Ellipse2D.Double(SX + 1 * R, SY + 5 * R, 2 * R, 2 * R),
new Ellipse2D.Double(SX + 0 * R, SY + 3 * R, 2 * R, 2 * R),
new Ellipse2D.Double(SX + 1 * R, SY + 1 * R, 2 * R, 2 * R)));
private boolean isRunning;
public void next() {
if (isRunning) {
list.add(list.remove(0));
}
}
public void setRunning(boolean isRunning) {
this.isRunning = isRunning;
}
@Override public void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(c == null ? Color.WHITE : c.getBackground());
g2.fillRect(x, y, getIconWidth(), getIconHeight());
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(ELLIPSE_COLOR);
g2.translate(x, y);
int size = list.size();
for (int i = 0; i < size; i++) {
float alpha = isRunning ? (i + 1) / (float) size : .5f;
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha));
g2.fill(list.get(i));
}
//g2.translate(-x, -y);
g2.dispose();
}
@Override public int getIconWidth() {
return WIDTH;
}
@Override public int getIconHeight() {
return HEIGHT;
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、スタートボタンを押すと(JTextArea
に表示している作業状況はダミーで、実際はThread.sleep()
で時間を稼いでいるだけ)アイコンがFireFox
風にアニメーションします。
アニメーションは、8
個の小さな円からアイコンを生成して、それぞれのインデックスを順に変更することで行っています。
- アイコンの生成
- リスト(
Vector
)に、座標の異なる円(Ellipse2D.Double
)を8
個生成して追加
- リスト(
- インデックスの変更
Timer
を使って、リストの先頭にある円を最後に移動
- 異なるアルファ値で円を描画
- インデックスに応じたアルファ値でそれぞれの円を描画
Java 1.6.0
では「小さな円(曲線)が円に見えなかった問題」が解消されてた(参考)
一々自分で座標を計算してnew Ellipse2D
を8
個も並べるのを避けたい、またはもうすこし正確に円を配置したい場合は、AffineTransform
などを使ってアイコンを生成する方法もあります。
class AnimeIcon2 implements Icon, Serializable {
private static final long serialVersionUID = 1L;
private static final Color ELLIPSE_COLOR = new Color(.5f, .8f, .5f);
private final List<Shape> list = new ArrayList<>();
private final Dimension dim;
private boolean isRunning;
public AnimeIcon2() {
super();
int r = 4;
Shape s = new Ellipse2D.Float(0, 0, 2 * r, 2 * r);
for (int i = 0; i < 8; i++) {
AffineTransform at = AffineTransform.getRotateInstance(
i * 2 * Math.PI / 8);
at.concatenate(AffineTransform.getTranslateInstance(r, r));
list.add(at.createTransformedShape(s));
}
//int d = (int) (r * 2*(1 + 2 * Math.sqrt(2)));
int d = (int) r * 2 * (1 + 3); // 2 * Math.sqrt(2) is nearly equal to 3.
dim = new Dimension(d, d);
}
@Override public int getIconWidth() {
return dim.width;
}
@Override public int getIconHeight() {
return dim.height;
}
@Override public void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(c == null ? Color.WHITE : c.getBackground());
g2.fillRect(x, y, getIconWidth(), getIconHeight());
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(ELLIPSE_COLOR);
int xx = x + dim.width / 2;
int yy = y + dim.height / 2;
g2.translate(xx, yy);
int size = list.size();
for (int i = 0; i < size; i++) {
float alpha = isRunning ? (i + 1) / (float) size : .5f;
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha));
g2.fill(list.get(i));
}
//g2.translate(-xx, -yy);
g2.dispose();
}
public void next() {
if (isRunning) {
list.add(list.remove(0));
}
}
public void setRunning(boolean isRunning) {
this.isRunning = isRunning;
}
}