简体   繁体   中英

Java Swing - paintComponent() not drawing my Threads

I want to add to an ArrayList of Thread 's which represent a ball with (x,y) coordinated and a move() method a new ball Thread every 5 seconds. So my JPanel implements Runnable and in there i add to the ArrayList a new ball Thread . In the paintComponent() method i use foreach loop to iterate the ArrayList of ball Thread 's and start their Thread which moves them and call for repaint() . Problem is ii don't see any drawing at all(Only the player drawing).

MyPanel.java :

public class MyPanel extends JPanel implements KeyListener,Runnable
{
    private static final long serialVersionUID = 1L;

    private static final Color BACKGROUND_COLOR = Color.WHITE; 
    private static final Color NPC_BALLS_COLOR = Color.RED;

    // The player is an oval
    private int playerRadius = 20;
    private int playerX;
    private int playerY;

    // True - first player position, false - otherwise
    private boolean playerPosition = true;

    // Array of all the balls threads
    private ArrayList<BallThread> balls = new ArrayList<BallThread>();

    private Thread generateBallsThread;

    public MyPanel()
    {
        this.setBackground(MyPanel.BACKGROUND_COLOR);
        this.setFocusable(true);
        this.addKeyListener(this);

        this.generateBallsThread = new Thread();
        generateBallsThread.start();
    }


    // Drawing

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        final double PANEL_WIDTH = this.getWidth();
        final double PANEL_HEIGHT = this.getHeight();

        if (this.playerPosition)
        {
            this.playerX = (int)(PANEL_WIDTH / 2 - this.playerRadius);
            this.playerY = (int)(PANEL_HEIGHT / 2 - this.playerRadius);
            this.playerPosition = false;
        }

        // Drawing the player
        g.setColor(Color.BLACK);
        g.fillOval(playerX,playerY, this.playerRadius * 2, this.playerRadius * 2);

        // Drawing npc's balls
        g.setColor(MyPanel.NPC_BALLS_COLOR);
        for (BallThread ball: this.balls)
        {
            ball.start();
            g.fillOval(ball.getBall().getX(), ball.getBall().getY(), 
                    ball.getBall().radius, ball.getBall().radius);
            repaint();
        }

    }

    // Keyboard listeners

    @Override
    public void keyPressed(KeyEvent e) 
    {
        switch (e.getKeyCode())
        {
            case KeyEvent.VK_W: // Up
            {
                this.playerY -= 5;
                repaint();
                break;
            }
            case KeyEvent.VK_S: // Down
            {
                this.playerY += 5;
                repaint();
                break;
            }
            case KeyEvent.VK_D: // Right
            {
                this.playerX += 5;
                repaint();
                break;
            }
            case KeyEvent.VK_A: // Left
            {
                this.playerX -= 5;
                repaint();
                break;
            }
        }
    }

    @Override
    public void keyReleased(KeyEvent e) 
    {

    }

    @Override
    public void keyTyped(KeyEvent e) 
    {

    }

    public int getBallXStartingPositionFromTop()
    {
        return (int) Math.random() * 101; // 0 - 100
    }

    //public int getBallYStartingPositionFromLeft()
    //{
    //  return (int) Math.random() * 101; // 0 - 100
    //}

    /**
     * 
     * 
     * 
     * Class for the balls threads.
     *
     */
    public class BallThread extends Thread
    {
        private Ball ball;

        public BallThread(Ball ball)
        {
            this.ball.setX(ball.getX());
            this.ball.setY(ball.getY());
        }

        @Override
        public void run() 
        {
            try 
            {
                this.ball.move();
                Thread.sleep(4000);
                repaint(); // Execute paintComponent() method
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }

        public Ball getBall()
        {
            return this.ball;
        }

        public void setBall(Ball ball) 
        {
            this.ball = ball;
        }


    }

    @Override
    public void run()
    {
        try
        {
            Thread.sleep(5000); // 5 seconds
            this.balls.add(new BallThread(new Ball(20,20)));

        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }








} // End of MyPanel class

Ball.java :

public class Ball 
{
    int x;
    int y;
    int velocity = 1;
    public int radius = 10;
    public boolean directionX = true; // True - right, false - left
    public boolean directionY = false; // True - up, false - down

    public static final int Y_STARTING_POSITION_FROM_TOP = 0;

    public Ball(int x, int y) 
    {
        this.x = x;
        this.y = y;
    }

    public Ball()
    {

    }

    public int getX() 
    {
        return this.x;
    }
    public void setX(int x) 
    {
        this.x = x;
    }
    public int getY()
    {
        return this.y;
    }
    public void setY(int y) 
    {
        this.y = y;
    }

    public void move()
    {
        if (this.directionX) // Right
        {
            this.x += this.velocity;
        }
        else // Left
        {
            this.x -= this.velocity;
        }
        if (this.directionY) // Up
        {
            this.y -= this.velocity;
        }
        else
        {
            this.y += this.velocity;
        }
    }


}

And i omitted a simple JFrame class and a main() who generates the JFrame with the JPanel added to it.

Any ideas why i don't get to see the drawing of the ball Thread 's?

    this.generateBallsThread = new Thread();
    generateBallsThread.start();

That does nothing. It is an empty Thread with no logic.

I think you want

    this.generateBallsThread = new BallsThread();
    generateBallThread.start();

Also, you should not be using a Thread for animation. You should be using a Swing Timer . Any logic that updates the state of a Swing component should be executed on the Event Dispatch Thread. Read the section from the Swing tutorial on Concurrency for more information. The tutorial also has a section on How to Use Swing Timers .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM