2016-02-27 57 views
0

我有这段代码,椭圆形状应该在实现可运行类时自动移动到右侧。但它似乎并没有移动。任何帮助深表感谢。提前致谢。当在java中使用线程实现可运行时,形状不会移动

package movingball; 

import java.awt.Color; 
import java.awt.Graphics; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class MovingBall extends JPanel{ 

    private static final int x = 30; 
    private static final int y = 30; 

    public MovingBall(){ 
     setBackground(Color.BLACK); 
    } 
    public MovingBall(int x, int y){ 
     x = this.x; 
     y = this.y; 
     repaint(); 
    } 
    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 

     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(500,700); 

     MovingBall movingBall = new MovingBall(); 
     frame.add(movingBall);  
     frame.setVisible(true); 

调用线程分配球对象

 BallUsingThread ball = new BallUsingThread(x, y); 
     Thread first = new Thread(ball); 
     first.start(); 

    } 

    @Override 
    public void paintComponent(Graphics canvas){ 
     super.paintComponent(canvas); 

     canvas.setColor(Color.BLUE); 
     canvas.fillOval(x, y, 100, 100); 
    } 

} 
/*Here is the second class. Where the oval shape should be moving. Any `suggestions here? Also just let me know if there are some codes need to be adjusted.*/ 

    class BallUsingThread implements Runnable{ 
     int x = 30; 
     int y = 30; 

     public BallUsingThread(int x, int y){ 
      this.x = x; 
      this.y = y; 
     } 
     @Override 
     public void run() { 
      for(;;){ 
       x++; 
       try { 
        Thread.sleep(2000); 
       } catch (InterruptedException ex) { 
        System.out.printf("Error",ex); 
       } 
      } 
     } 

    } 

回答

2

这...

private static final int x = 30; 
private static final int y = 30; 

使得unchangable值...

这...

class BallUsingThread implements Runnable{ 
    int x = 30; 
    int y = 30; 

    public BallUsingThread(int x, int y){ 
     this.x = x; 
     this.y = y; 
    } 
    @Override 
    public void run() { 
     for(;;){ 
      x++; 

是别人毫无意义。由于Java传递变量的方式,对值x的任何修改只会在BallUsingThread类的上下文中进行,MovingBall将不会看到它们,即使您可以重新绘制它们。

相反,你应该传递的MovingBall一个参考BallUsingThread并提供BallUsingThread召呼其更新球的x位置,例如...

import java.awt.Color; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class MovingBall extends JPanel { 

    private int ballX = 30; 
    private int ballY = 30; 

    public MovingBall() { 
     setBackground(Color.BLACK); 
    } 

    public MovingBall(int x, int y) { 
     x = this.ballX; 
     y = this.ballY; 
     repaint(); 
    } 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 

     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(500, 700); 

     MovingBall movingBall = new MovingBall(); 
     frame.add(movingBall); 
     frame.setVisible(true); 

     BallUsingThread ball = new BallUsingThread(movingBall); 
     Thread first = new Thread(ball); 
     first.start(); 

    } 

    @Override 
    public void paintComponent(Graphics canvas) { 
     super.paintComponent(canvas); 

     canvas.setColor(Color.BLUE); 
     canvas.fillOval(ballX, ballY, 100, 100); 
    } 

    public void updateBall() { 
     if (EventQueue.isDispatchThread()) { 
      ballX++; 
      repaint(); 
     } else { 
      SwingUtilities.invokeLater(new Runnable() { 
       @Override 
       public void run() { 
        updateBall(); 
       } 
      }); 
     } 
    } 

} 

/*Here is the second class. Where the oval shape should be moving. Any `suggestions here? Also just let me know if there are some codes need to be adjusted.*/ 
class BallUsingThread implements Runnable { 

    private MovingBall movingBall; 

    public BallUsingThread(MovingBall mb) { 
     movingBall = mb; 
    } 

    @Override 
    public void run() { 
     for (;;) { 
      movingBall.updateBall(); 
      try { 
       Thread.sleep(500); 
      } catch (InterruptedException ex) { 
       System.out.printf("Error", ex); 
      } 
     } 
    } 

} 

现在,Swing是不是方法线程安全的(我已经占了),但有一个简单的解决方案...

使用一个Swing Timer,而不是...

MovingBall

import java.awt.Color; 
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 MovingBall extends JPanel { 

    private int ballX = 30; 
    private int ballY = 30; 

    public MovingBall() { 
     setBackground(Color.BLACK); 
    } 

    public MovingBall(int x, int y) { 
     x = this.ballX; 
     y = this.ballY; 
     repaint(); 
    } 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 

     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(500, 700); 

     MovingBall movingBall = new MovingBall(); 
     frame.add(movingBall); 
     frame.setVisible(true); 

     BallUsingTimer ball = new BallUsingTimer(movingBall); 
     Timer timer = new Timer(40, ball); 
     timer.start(); 
    } 

    @Override 
    public void paintComponent(Graphics canvas) { 
     super.paintComponent(canvas); 

     canvas.setColor(Color.BLUE); 
     canvas.fillOval(ballX, ballY, 100, 100); 
    } 

    public void updateBall() { 
     ballX++; 
     repaint(); 
    } 

} 

BallUsingTimer

public class BallUsingTimer implements ActionListener { 

    private MovingBall movingBall; 

    public BallUsingTimer(MovingBall mb) { 
     movingBall = mb; 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     movingBall.updateBall(); 
    } 

} 

详情请参阅Concurrency in SwingHow to use Swing Timers

+0

明白了你的观点。谢谢。 –

0

你的线程简单地更新程序存储器(它增加x每个阶段)。窗口子系统不知道组件的脏状态,所以不调用paint方法。

您必须致电JComponent.repaint()并且请注意,该调用必须发生在UI线程中(例如使用SwingUtilities.invokeLater())。

请注意,通过这种方式,您的程序没有任何顺利运行的机会,并且会爆发大量的CPU周期。对于动画和/或游戏,您需要一个循环器,让您可以控制帧的运行时间以及一秒钟内的帧数。

+1

'repaint'实际上是为数不多的线程安全的方法,但是'MovingBall'将永远不会看到的变化是' BallUsingThread'变成'x',所以它毫无意义 – MadProgrammer

+0

不知道。谢谢 – Raffaele