2016-02-27 40 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

相關問題