问题
I am trying to display the two circles moving together on a single frame through two different classes. But only one is shown moving at a time,even though value of "x" is changing continuously in class child1, paintComponent() is only taking the value of "x1" and showing the circle in moving from class child2.
If two separate frames are assigned to both the classes they works perfectly fine. Here is my code
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test13
{
public static void main(String[] args)
{
child1 c1 = new child1();
child2 c2 = new child2();
JFrame f1 = new JFrame("Frame Test1");
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//passing a single JFrame to both methods as parameters
c1.cfunc1(f1);
c2.cfunc2(f1); // but this line always hides the upper one
f1.setSize(1000,700);
f1.setVisible(true);
}
}
class child1 extends JPanel implements ActionListener
{
int x,y;
int delay1;
Timer timer1; //timer for 1st class constructor
child1()
{
x=1;
y=100;
timer1 = new Timer(50,this);
}
@Override
public void actionPerformed(ActionEvent e)
{
if(x <= 500)
{
x += 1;
y = 100;
repaint();
}
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x, y, 10, 10);
}
void cfunc1(JFrame f1)//passing JFrame as parameter
{
child1 c1 = new child1();
f1.add(c1);
c1.timer1.start(); //timer started at the end of class1
}
}
class child2 extends JPanel implements ActionListener
{
int x1,y1;
int delay2;
Timer timer2;
child2()
{
x1 = 500;
y1 = 100;
timer2 = new Timer(50,this);//timer for 2nd class constructor
}
@Override
public void actionPerformed(ActionEvent e)
{
if(x1 <= 500)
{
x1 -= 1;
y1 = 100;
repaint();
}
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x1, y1, 10, 10);
}
void cfunc2(JFrame f1)//passing JFrame as parameter
{
child2 c2 = new child2();
f1.add(c2);
c2.timer2.start();//timer started for 2nd class
}
}
回答1:
When two components are added to a single constraint of a BorderLayout
(the default layout for a JFrame
), only one is displayed.
The typical way to do this is not to design the custom painting in a JComponent
(like JPanel
) but instead to have them as simple classes which can paint(Graphics)
or draw(Graphics)
when requested to do so.
Then extend a single JComponent
that iterates a list of the drawable components and paints each one.
回答2:
Don't create individual classes (child1, child2) for each object. What if you want 50 objects? Instead you create a class that accepts parameters that allows you to customize the object.
This example shows how you might:
- create a generic Ball class.
- uses a Swing Timer for animation of the balls
- create a panel that does custom painting by invoking the
draw(...)
method of each Ball.
Here is the code:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class BallAnimation4
{
private static void createAndShowUI()
{
BallPanel panel = new BallPanel();
JFrame frame = new JFrame("BallAnimation4");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.setSize(800, 600);
frame.setLocationRelativeTo( null );
//frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible( true );
panel.addBalls(5);
panel.startAnimation();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
class BallPanel extends JPanel implements ActionListener
{
private ArrayList<Ball> balls = new ArrayList<Ball>();
public BallPanel()
{
setLayout( null );
setBackground( Color.BLACK );
}
public void addBalls(int ballCount)
{
Random random = new Random();
for (int i = 0; i < ballCount; i++)
{
Ball ball = new Ball();
ball.setRandomColor(true);
ball.setLocation(random.nextInt(getWidth()), random.nextInt(getHeight()));
ball.setMoveRate(32, 32, 1, 1, true);
// ball.setMoveRate(16, 16, 1, 1, true);
ball.setSize(32, 32);
balls.add( ball );
}
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for (Ball ball: balls)
{
ball.draw(g);
}
}
public void startAnimation()
{
Timer timer = new Timer(75, this);
timer.start();
}
public void actionPerformed(ActionEvent e)
{
move();
repaint();
}
private void move()
{
for (Ball ball : balls)
{
ball.move(this);
}
}
class Ball
{
public Color color = Color.BLACK;
public int x = 0;
public int y = 0;
public int width = 1;
public int height = 1;
private int moveX = 1;
private int moveY = 1;
private int directionX = 1;
private int directionY = 1;
private int xScale = moveX;
private int yScale = moveY;
private boolean randomMove = false;
private boolean randomColor = false;
private Random myRand = null;
public Ball()
{
myRand = new Random();
setRandomColor(randomColor);
}
public void move(JPanel parent)
{
int iRight = parent.getSize().width;
int iBottom = parent.getSize().height;
x += 5 + (xScale * directionX);
y += 5 + (yScale * directionY);
if (x <= 0)
{
x = 0;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}
if (x >= iRight - width)
{
x = iRight - width;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}
if (y <= 0)
{
y = 0;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
if (y >= iBottom - height)
{
y = iBottom - height;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
}
public void draw(Graphics g)
{
g.setColor(color);
g.fillOval(x, y, width, height);
}
public void setColor(Color c)
{
color = c;
}
public void setLocation(int x, int y)
{
this.x = x;
this.y = y;
}
public void setMoveRate(int xMove, int yMove, int xDir, int yDir, boolean randMove)
{
this.moveX = xMove;
this.moveY = yMove;
directionX = xDir;
directionY = yDir;
randomMove = randMove;
}
public void setRandomColor(boolean randomColor)
{
this.randomColor = randomColor;
switch (myRand.nextInt(3))
{
case 0: color = Color.BLUE;
break;
case 1: color = Color.GREEN;
break;
case 2: color = Color.RED;
break;
default: color = Color.BLACK;
break;
}
}
public void setSize(int width, int height)
{
this.width = width;
this.height = height;
}
}
}
Normally you wouldn't make the classes static.
来源:https://stackoverflow.com/questions/28859324/how-to-move-two-circles-together-in-a-jframe-from-two-different-classes