41848


初心者です、質問失礼します。  
現在`java`の`swing`を使って、キー入力したら円が広がりながら消えていく、というパーティクルのようなアニメーションを作りたいと思っています。`JPanel`を継承した`SpreadCircle`でキー入力を監視して、入力されたら`Circle`をインスタンス化してアニメーション開始するのですが、その際`repaint()`を呼び出しているのにも関わらず画面に変化がありません。  
なぜうまくアニメーションが表示されないのでしょうか？

また、`paintComponent`の仕組みがよくわかっていないため、`JPanel`を継承したクラス以外から`repaint()`や`g.fillOval()`のような`Graphics`の情報を更新する方法がわかりません。  
色々と考えて`Graphics2D`の変数や`SpreadCircle`の変数を`static`にして見たのですがうまくいきませんでした。もっとスマートに`Graphics`の更新(`JPanel`の`fillOval`や`repaint`等)を行う方法があれば教えていただけると幸いです。

Frame_of_SpreadCircle.java

[code]

    import javax.swing.JFrame;
    
    public class Frame_of_SpreadCircle{
        static SpreadCircle panel = new SpreadCircle();
    
        public static void main(String args[]) {
            JFrame frame = new JFrame("SpreadCircle");
    
            frame.addKeyListener(panel);
            frame.add(panel);
            frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);
        }
    }
    
[/code]

SpreadCircle.java

[code]

    public class SpreadCircle extends JPanel implements KeyListener {
        public static final int size = 50;
        public static Graphics2D g2;
    
        public SpreadCircle(){
            super();
            setPreferredSize(new Dimension(600,400));
            setBackground(Color.GRAY);
        }
    
        @Override
        public void keyTyped(KeyEvent e) {
            // TODO 自動生成されたメソッド・スタブ
            Circle circle = new Circle(size);
            circle.drawCircle();
        }
    
        public void paintComponent(Graphics g) {
            g2 = (Graphics2D) g;
            super.paintComponent(g2);
            g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
    
        }
    
        @Override
        public void keyPressed(KeyEvent e) {
            // TODO 自動生成されたメソッド・スタブ
    
        }
    
        @Override
        public void keyReleased(KeyEvent e) {
            // TODO 自動生成されたメソッド・スタブ
    
        }
    }
    
[/code]

Circle.java

[code]

    public class Circle implements ActionListener  {
        int x;
        int y;
        int l;
        int a;
        int b;
        int c;
        int alpha = 100;
        int time = 0;
        Timer timer = new Timer(60,this);
        Color color ;
    
        public Circle(int w) {
            l = w;
            x = (int) (Math.random() * 300);
            y = (int) (Math.random() * 200);
    
            a = (int) (Math.random() * 256);
            b = (int) (Math.random() * 256);
            c = (int) (Math.random() * 256);
            color = new Color(a,b,c,alpha);
    
            timer.start();
        }
    
        public void drawCircle() {
            SpreadCircle.g2.setColor(color);
            SpreadCircle.g2.fillOval(x, y, l, l);
            Frame_of_SpreadCircle.panel.repaint();
        }
    
        public void actionPerformed(ActionEvent e) {
            // TODO 自動生成されたメソッド・スタブ
            if(time < 10) {
                l += 3;
                alpha -= 10;
    
                drawCircle();
                Frame_of_SpreadCircle.panel.repaint();
            }else {
                SpreadCircle.g2.dispose();
                timer.stop();
            }
            time++;
        }
    }
    
[/code]


CC BY-SA 3.0
2018-02-19T12:15:04.323
41842
2018-02-20T06:04:06.960
2018-02-20T06:04:06.960
46
24534
question
java swing
JPanelの持つGraphicsを別クラスから更新したい


まず、 paintComponent(Graphics g) で渡された Graphics
オブジェクトを保存しておいて、paintComponent(Graphics g)
を抜けた後に、呼び出してはいけません。ほかのクラスに描画処理を委譲したい場合は paintComponent() から Graphics
オブジェクトを渡してメソッドを呼び出しましょう。

  * timer は Circle の状態(アニメーションのフレーム)を更新して repaint() を呼び出す
  * Circle のアニメーション処理が終わったら timer を停止
  * repaint() の呼び出しにより paintComponent(Graphics g)が呼び出される
  * paintComponent(Graphics g) から Circle#drawCircle(Graphics2D g2) が呼び出される

大分いじったため期待する動作とは異なるかもしれませんが、可能な限り原型を残して修正してみた結果を以下に示します。

FrameOfSpreadCircle.java

[code]

    import javax.swing.JFrame;
    
    public class FrameOfSpreadCircle {
    
        static SpreadCirclePanel panel = new SpreadCirclePanel();
    
        public static void main(String args[]) {
            JFrame frame = new JFrame("SpreadCircle");
    
            frame.addKeyListener(panel);
            frame.add(panel);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);
        }
    }
    
[/code]

SpreadCirclePanel.java

[code]

    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.event.KeyEvent;
    import java.awt.event.KeyListener;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    public class SpreadCirclePanel extends JPanel implements KeyListener, ActionListener {
    
        public static final int CIRCLE_SIZE = 50;
        private Circle circle;
        private final Timer timer;
    
        public SpreadCirclePanel() {
            super();
            setPreferredSize(new Dimension(600, 400));
            setBackground(Color.GRAY);
            timer = new Timer(60, this);
        }
    
        @Override
        public void keyTyped(KeyEvent e) {
            if (circle == null) {
                circle = new Circle(CIRCLE_SIZE);
                timer.start();
            }
        }
    
        @Override
        public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            super.paintComponent(g2);
    
            // アンチエイリアスを有効に設定
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    
            if (circle != null) {
                circle.drawCircle(g2); // 円を描画
            }
        }
    
        @Override
        public void keyPressed(KeyEvent e) {
        }
    
        @Override
        public void keyReleased(KeyEvent e) {
        }
    
        public void actionPerformed(ActionEvent ae) {
            if (circle != null) {
                circle.updateCircle();
                if (circle.isEnd()) {
                    timer.stop();
                    circle = null;
                }
                repaint();
            }
        }
    
    }
    
[/code]

Circle.java

[code]

    import java.awt.Color;
    import java.awt.Graphics2D;
    
    public class Circle {
    
        int centerX, centerY;
        int l;
        int a;
        int b;
        int c;
        int alpha = 100;
        int time = 0;
    
        public Circle(int w) {
            l = w;
            centerX = (int) (Math.random() * 300);
            centerY = (int) (Math.random() * 200);
    
            a = (int) (Math.random() * 256);
            b = (int) (Math.random() * 256);
            c = (int) (Math.random() * 256);
        }
    
        public void updateCircle() {
            if (time < 10) {
                l += 3;
                alpha -= 10;
                time++;
            }
        }
    
        public void drawCircle(Graphics2D g2) {
            Color color = new Color(a, b, c, alpha);
            g2.setColor(color);
            g2.fillOval(centerX - l/2, centerY - l/2, l, l);
        }
    
        public boolean isEnd() {
            return time >= 10;
        }
    }
    
[/code]


CC BY-SA 3.0
2018-02-19T15:43:01.073
41848
2018-02-20T01:45:50.783
2018-02-20T01:45:50.783
27410
27410
41842
answer