【问题标题】:Using Thread to Create Moving Ball Applet使用线程创建移动球小程序
【发布时间】:2013-06-27 22:14:15
【问题描述】:

最终让球移动,但应用程序无法完美执行,我仍然不确定 run() 方法设置......我认为我不需要它,但它是任务的一部分。如果有更好的方法,请告诉我。

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;

public class BouncingBallApp extends JFrame
{
    //start of main method
    public static void main(String[] args)
    {
       //crate container
       Container container = new Container();
       //crate BouncingBallApp instance
       BouncingBallApp bBalls = new BouncingBallApp();
        //set the window closing feature(close with X click)
       bBalls.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       //crate boucing ball panel(BBP) instance and add
       BouncingBallPanel BBP = new BouncingBallPanel();
       container.add(BBP);
       //make the BBP the MouseListner
       bBalls.addMouseListener(BBP);
       //set window background and size
       bBalls.setBackground(Color.WHITE);
       bBalls.setSize(400, 300);
       BBP.setSize(400, 300);
       BBP.setLayout(null);
       bBalls.setContentPane(BBP);
       //set window visible
       bBalls.setVisible(true);
    }//end of main method
}//end of Class BouncingBall App


class BouncingBallPanel extends JPanel implements MouseListener
{
    //create an empty array for 20 Ball objects
    public Ball[] array; 
    private int count = 0;
    Random generator = new Random();

    public BouncingBallPanel()
    {
        array = new Ball[20];
    }

        public void mouseClicked(MouseEvent event)
    {
        array[count] = new Ball(this);
        count++;
        if( count == 1)
        {
            final Runnable update = new Runnable()
            {
                public void run()
                {
                    for (int j = 0; j < array.length; j++)
                    {
                        if(array[j] != null)
                        {
                            array[j].move();
                        }//end of if
                    }//end of for 
                }//end of run method
            };//end of runnalbe update
            (new Thread(new Ball(this))).start();
            Runnable graphic = new Runnable()
            {
                public void run()
                {
                    while(true)
                    {
                        try
                        {
                            EventQueue.invokeLater(update);
                            Thread.sleep(generator.nextInt(10 +100));
                        }catch (InterruptedException exp){}
                    }//end of while
                }//end of run 
            };//end of runnable
            new Thread(graphic).start();
        }//end of if  
    }//end of mouseClicked method

    //empty interfaces for mouse events
    public void mouseExited(MouseEvent event){}
    public void mouseReleased(MouseEvent event){}
    public void mouseEntered(MouseEvent event){}
    public void mousePressed(MouseEvent event){}   

    //paint component method
    public void paintComponent(Graphics g)
    {
     super.paintComponent(g);
     Graphics2D g2d = (Graphics2D) g;
     //loop for each ball and draw all balls in array
     for(int i = 0; i < array.length; i++)
     {
        if(array[i] != null)
        {
         g2d.setColor(array[i].getColor());
         g2d.fillOval((int)array[i].getX(), (int)array[i].getY(), (int)array[i].getDiameter(), (int)array[i].getDiameter());
        }
     }//end of for loop
    }//end of paintComponent loop
}//end of Class BouncingBallPanel

class Ball implements Runnable
{
    //set up variables
    private double x;
    private double y;
    private int deltaX;
    private int deltaY;
    private double diameter;
    private Color color;
    BouncingBallPanel BBP2;

    Random random = new Random();

    public Ball(BouncingBallPanel a) 
    {
        x = random.nextInt(400);
        y = random.nextInt(300);
        deltaX = 1 + random.nextInt(10);
        deltaY = 1 + random.nextInt(10);
        diameter = 5 + random.nextInt(20);
        color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
        BBP2 = a;
    }// end of constructor

    public double getX() 
    {
        return x;
    }

    public double getY() {
            return y;
    }

    public double getDiameter() {
        return diameter;
    }

    public Color getColor() {
        return color;
    }

    public void move() {
        x += deltaX;
        y += deltaY;

        if (x > 400 - getDiameter()|| x <0) 
        {
            deltaX = -deltaX;
        }

        if (y > 300 - getDiameter() || y < 0)
        {
            deltaY = -deltaY;
        }

    }// end of method move
    @Override
    public void run()
    {
        while(true)
         { 
            move();
            BBP2.repaint();       
            try{
               Thread.currentThread().sleep(10 + random.nextInt(100));
            }catch(InterruptedException exp){} 
           }//end of while 
    }//end of run method
}//end of Ball

【问题讨论】:

    标签: java multithreading swing


    【解决方案1】:

    两个问题:

    1. 你永远不会为球创建线程。仅仅创建一个对象Runnable 并不会隐式创建一个线程。你在构造函数中需要这样的东西:

      new Thread(this).start();

    2. 在 Swing 事件模型中,使用Timer 优于后台线程。使用线程,如果在绘制窗口时对象移动,您将看到图形工件。

    【讨论】:

    • +1。 @user2520823 setSizesetLayout(null);,我已经对代码感到畏缩了。使用Layout Managers!并在必要时和必要时覆盖 getPreferredSizeJPanel。我也看不到 SwingUtilities.invokeXXX 块在哪里,这是需要的,否则会间歇性发生意外行为(现在发生,而且每次都很难重现)阅读 Concurrency in Swing 适用于小程序和 Swing 虽然小程序将在 init() 中使用 invokeAndWait .
    • @DavidKroukamp:实际上,在这种情况下,您不需要将 GUI 构造包装在 invokeLater 中 - 在第一个组件可显示后,主线程中不会运行任何代码。但同意无论如何这是一种不好的做法。
    • 没有代码在主线程中运行据我所知main(String[] args) 中的所有代码都在初始/主线程上运行,据我所知在 Swing 组件/对象上调用或修改的方法(除非指定线程安全,如 repaint)应包装在 invokeXXX 块中(检查链接 Concurrency in swing in my previous comment)以确保它在Event Dispatch Thread 而不是任何其他线程。正如我所说,现在可能没有错误/伪影,但在其他系统上可能/将会发生意外行为,并且可能随着代码变得越来越长
    • @DavidKroukamp:见this article
    • 我不能说我完全同意,尤其是当我阅读 之后,GUI 中的组件立即通过 setVisible(或 show)调用显示。从技术上讲,setVisible 调用是不安全的,因为组件已经通过 pack 调用实现。但是,由于该程序还没有可见的 GUI,在 setVisible 返回之前发生绘制调用的可能性极小。 但我明白你的意思。大声笑技术性让我们把它留在那里。
    猜你喜欢
    • 2013-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-17
    • 2018-10-09
    相关资源
    最近更新 更多