在一个JFrame中同时处理两个JPanel
我是新手到java swing。 在尝试使用图形时,我遇到了这个问题。 我无法在网络上找到合适的解决方案。 所以我想发布在这里。
所以现在让我们来解决我的问题。 首先,我将解释我想做什么。 然后我将解释我的问题。
我试图让两个球在JFrame中同时向不同的方向移动。 (基本上我想做类似连锁反应的游戏,当你点击一个装满的盒子时,球会同时向不同的方向移动)。
在这里我创建两个(截至目前)两个球的JPanels,我试图同时在JFrame上移动。
这是我试过的代码,
public class chainGraphics扩展JPanel实现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;inewX;i--){ changeX=i; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } repaint(); } } } if((newX-oldX)==0){ if(oldY<newY){ for(int i=oldY;inewY;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(); } }
}
在这里,我看不到两个球同时移动。 我猜有一个问题。 我能够看到球只沿y方向移动。 (但我希望两个球同时移动,因为我创造了两个线程)
而且我还注意到如果我先创建g1对象然后再创建g对象,那么球只会沿x方向移动。
我认为Jframe只允许一次使用1个JPanel。 (我将JPanel添加到Frame彻底的构造函数中)。 因此,最后将JPanel添加到框架中,它允许对其进行处理。 是这样吗 ? 如果我现在该怎么办。我的要求是我想在不同方向同时移动球。 谢谢。
“不,我试图用两个线程画出两个球”
-
不要尝试将面板的两个实例添加到容器中。 只需使用
Ball
对象的数据结构(我更喜欢List)并在paintComponent
方法中循环它们。 每个球都可以有一个drawBall(Graphics g)
方法,你可以在paintComponent
方法中调用它,并向它传递Graphics
上下文 -
使用Swing
Timer
并忘记线程。Thread.sleep
不是你在Swing中的朋友。 请参见如何使用Swing Timers -
在Timer中,只需更改每个
Ball
对象的位置/轨迹并调用repaint()
。 您可以在Ball
类中使用可以改变方向的方法。 -
在Event Dispatch Thread上运行Swing应用程序。 您可以通过将
main
方法代码包装在SwingUtilities.invokeLater..
。 请参见初始线程
这是一个例子
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 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); } }); } }