绘制2个球在Java上向不同方向移动但是一个消失了

时间:2013-03-12 03:50:06

标签: java multithreading swing jpanel

我正在尝试创建一个可以绘制2个球的程序,其中一个在北方中心,另一个在南方中心。我需要向不同方向移动球,北方的第一个球随机向南移动,另一个球向南移动向北移动。我可以让北中心的球向下移动,但是南方的第二个球在被拉出后就消失了。

PS:我需要有2个内部类Ball1Ball2。请帮忙。非常感谢。

1 个答案:

答案 0 :(得分:3)

...问题

    事件调度线程中的
  1. while-loop调整图形对象的位置
  2. Thread.sleep方法中
  3. paint
  4. 不致电super.paintComponent
  5. 使用paintComponent方法更新对象的状态。
  6. Swing使用单线程模型,负责(其中包括)将重绘请求分派给所有组件。

    在EDT中执行任何停止处理这些事件的操作,将阻止Swing重新绘制UI。这将使您的动画从一开始就突然从一开始就消失。

    查看Concurrency in 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);
            }
    
        }
    
    }