working on two JPanels simultaneously in a single

2019-01-12 11:31发布

问题:

I m a newbie to java swing . And when trying with graphics i got stuck with this. I could'nt find a proper solution in web . So i thought of posting here .

so now lets come to my problem . First i will explain what i m trying to do . And then i will explain about my problem.

I m trying to make two balls move in different directions simultaneously in a JFrame . (Basically i thought of doing like chain Reaction game in which when you click on a filled box, the balls will move simultaneously in different directions ) .

Here i m creating two (as of now) JPanels for two balls which i m trying to move on a JFrame SIMULTANEOUSLY .

here is the code which i tried out ,

public class chainGraphics extends JPanel implements Runnable{

int oldX,oldY,newX,newY;
int changeX,changeY;
Container myPane;
public chainGraphics(int oldX,int oldY,int newX,int newY,Container myPane) {
    // TODO Auto-generated constructor stub
    this.myPane=myPane;
    this.oldX=oldX;
    this.oldY=oldY;
    this.newX=newX;
    this.newY=newY;
    myPane.add(this);

}

public void paintComponent(Graphics g) {

    //super.paintComponent(g);
    System.out.println("hj");
    g.drawOval(changeX,changeY, 40, 40);

}


@Override
public void run()   {


    System.out.println("hii");
    changeX =oldX;
    changeY = oldY;

    if((newY-oldY)==0){
        if(oldX<newX){
            for(int i=oldX;i<newX;i++){
                System.out.println("hii123");
                changeX = i;
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }

                repaint();
            }
        }
        else    {
            for(int i=oldX;i>newX;i--){
                changeX=i;
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                repaint();
            }
        }

    }
    if((newX-oldX)==0){
        if(oldY<newY){
            for(int i=oldY;i<newY;i++){
                changeY=i;
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                repaint();
            }
        }
        else    {
            for(int i=oldY;i>newY;i--){
                changeY=i;
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                repaint();
            }
        }       
    }
}

public static void main(String[] args)  {

    JFrame gui = new JFrame();
    gui.setTitle("Chain Reaction ;-) ");
    gui.setSize(650,650);
    gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    gui.setLocationRelativeTo(null);
    gui.setVisible(true);
    Container Pane = gui.getContentPane();
    chainGraphics g = new chainGraphics(100,200,300,200,Pane);  
            chainGraphics g1 = new chainGraphics(200,100,200,300,Pane); 
    Thread t1 = new Thread(g);
    t1.start();     
    Thread t2 = new Thread(g1);
    t2.start();


    try {
        t1.join();
                    t2.join();      
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

}

Here i couldnt see two balls moving simultaneously . There is a problem i guess. i could able to see ball moving along y direction only . (but i want both ball to move simutaneously, since i create two threads)

And i also noticed if i create g1 object first and then g object , then the ball moves along x direction only .

I think the Jframe allows to work on 1 JPanel only at a time . (And i am adding the JPanel to Frame thorough Constructor ) . so which ever JPanel is added lastly to frame ,it allows to work on it . is it so ? IF yes what should i do now .My requirement is i want to move balls simultaneously in different Directions. Thanks.

回答1:

"No i am trying to draw two balls using two threads"

  1. Don't try and add two instances of your panel to a container. Just Use a data structure (I prefer List) of Ball objects and loop through them in the paintComponent method. Each ball can have a drawBall(Graphics g) method that you can call in the paintComponent method, passing to it the Graphics context

  2. Use a Swing Timer and forget about the threading. Thread.sleep isn't your friend in Swing. See How to use Swing Timers

  3. In the Timer, just change the locations/trajectory of locations of each Ball object and call repaint(). You can have methods in your Ball class that will change direction.

  4. Run Swing apps on the Event Dispatch Thread. You can do so by wrapping your main method code in a SwingUtilities.invokeLater... See Initial Threads


Here's an example

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class MoveBalls extends JPanel {

    private static final int D_W = 500;
    private static final int D_H = 300;

    private List<Ball> balls;

    public MoveBalls() {
        Random rand = new Random();
        balls = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            int randX = rand.nextInt(D_W);
            int randY = rand.nextInt(D_H);
            balls.add(new Ball(randX, randY));
        }

        Timer timer = new Timer(15, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                for (Ball ball : balls) {
                    ball.animate();
                }
                repaint();
            }
        });
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Ball ball : balls) {
            ball.drawBall(g);
        }
    }

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

    public class Ball {

        int x = 0;
        int y = 0; // Current ball position
        int dx = 4; // Increment on ball's x-coordinate
        int dy = 4; // Increment on ball's y-coordinate
        int radius = 15; // Ball radius

        public Ball(int x, int y) {
            this.x = x;
            this.y = y;
        }
        Color color = new Color((int) (Math.random() * 256),
                (int) (Math.random() * 256), (int) (Math.random() * 256));

        public void drawBall(Graphics g) {
            g.setColor(color);
            g.fillOval(x - radius, y - radius,
                    radius * 2, radius * 2);
        }

        public void animate() {
            if (x < 0 || x > getWidth()) {
                dx = -dx;
            }
            if (y < 0 || y > getHeight()) {
                dy = -dy;
            }
            // Adjust ball position
            x += dx;
            y += dy;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MoveBalls());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}