-3

北の中央と南の中央に2つのボールが描かれるプログラムを作成しようとしています。北の最初のボールがランダムに南に向かって移動し、南の中央にあるもう1つのボールが北に向かって移動するように、ボールをさまざまな方向に移動する必要があります。ノースセンターのボールを下に動かすことはできますが、南の2番目のボールは引かれた直後に消えます。

Ball1PS:とである2つの内部クラスが必要ですBall2。助けてください。どうもありがとう。

4

1 に答える 1

3

問題...

  1. while-loopグラフィックオブジェクトの位置を調整するイベントディスパッチスレッドで
  2. Thread.sleeppaintメソッドで。
  3. 通話していないsuper.paintComponent
  4. メソッド内のオブジェクトの状態を更新しますpaintComponent

Swing は、すべてのコンポーネントへの再描画要求のディスパッチなどを担当するシングル スレッド モデルを使用します。

これらのイベントの処理を停止する操作を EDT で実行すると、Swing が UI を再描画できなくなります。これにより、アニメーションが最初から最後まで 1 つのステップで突然進んだように見えます。

詳細については、Swing での同時実行をご覧ください。特に、Initial ThreadsHow to use Swing Timers をご覧ください。

ポイント4を強調する必要があります-

再描画サイクルは制御できません。再描画要求は、要求していないさまざまな理由で発生する可能性があります。これらの理由により、オブジェクトが自分の制御を超えて更新されたり、不要な場合に更新されたりします。paintメソッド内から UI のどの部分の状態も変更しないでください。

簡単な例

これは非常に単純な例ですが、Swing でアニメーションを行うために理解する必要がある基本的な概念を示しています。

public class SimpleBouncyBall {

    public static void main(String[] args) {
        new SimpleBouncyBall();
    }

    public SimpleBouncyBall() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new CourtPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class CourtPane extends JPanel {

        private Ball ball;
        private int speed = 5;

        public CourtPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Rectangle bounds = new Rectangle(new Point(0, 0), getSize());
                    if (ball == null) {
                        ball = new Ball(bounds);
                    }
                    speed = ball.move(speed, bounds);
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); 
            if (ball != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                Point p = ball.getPoint();
                g2d.translate(p.x, p.y);
                ball.paint(g2d);
                g2d.dispose();
            }
        }

    }

    public class Ball {

        private Point p;
        private int radius = 12;

        public Ball(Rectangle bounds) {

            p = new Point();
            p.x = 0;
            p.y = bounds.y + (bounds.height - radius) / 2;

        }

        public Point getPoint() {
            return p;
        }

        public int move(int speed, Rectangle bounds) {

            p.x += speed;
            if (p.x + radius >= (bounds.x + bounds.width)) {

                speed *= -1;
                p.x = ((bounds.x + bounds.width) - radius) + speed;

            } else if (p.x <= bounds.x) {

                speed *= -1;
                p.x = bounds.x + speed;

            }

            p.y = bounds.y + (bounds.height - radius) / 2;

            return speed;

        }

        public void paint(Graphics2D g) {
            g.setColor(Color.RED);
            g.fillOval(0, 0, radius, radius);
        }

    }

}
于 2013-03-12T03:58:20.513 に答える