2012-12-25 12 views
2

這是我在stackoverflow上的第一篇文章,我希望有人可以幫我解決我在這裏遇到的問題。Java:repaint()不要調用for循環中的paintComponent()

我正在處理的問題是repaint()問題,有些人會認爲我只是沒有足夠的搜索這些論壇來解決我的問題,但我已經廣泛地查找,沒有任何工作。在下面的代碼中,我嘗試在for循環中調用drawB來獲得數組的大小,該代碼正常工作。 for循環調用drawB 20次左右。在drawB中,我希望設置一個圖像(其取決於數組中的數字),然後調用repaint(),然後在子類GameCanvas中調用paintComponent()

問題是,paintComponant沒有在這個初始化中運行。然而,repaint()是否在我製作gameLoop()的循環中運行,但我需要在gameLoop()之前進行此初始化。

任何人都有任何線索怎麼回事,或如何解決它?

package engine; 

import java.awt.*; 
import java.awt.event.*; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 

import javax.imageio.ImageIO; 
import javax.swing.*; 

public class GameMain extends JFrame // main class for the game as a Swing application 
{  

// Define constants for the game 
static final int CANVAS_WIDTH = 800; // width and height of the game screen 
static final int CANVAS_HEIGHT = 600; 
static final int UPDATE_RATE = 4; // number of game update per second 
static final long UPDATE_PERIOD = 1000000000L/UPDATE_RATE; // nanoseconds 

String path; 
BufferedImage image; 

private GameCanvas canvas; 

// Constructor to initialize the UI components and game objects 
public GameMain() 
{ 
    gameInit(); 

    image = null; 
    canvas = new GameCanvas(); 
    canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT)); 
    this.setContentPane(canvas); 


    this.setDefaultCloseOperation(EXIT_ON_CLOSE); 
    this.pack(); 
    this.setTitle("Blockcraft!"); 
    this.setVisible(true); 
} 

public void gameInit() 
{ 
    dispArray(); 
    gameStart(); 
} 

public void dispArray() 
{ 
    int tempLevel[][] = new int[][] {{1,1,1,1},{6,2,2,2},{3,3,3,3},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4}}; 
    int widthTemp = tempLevel[0].length; 
    int heightTemp = tempLevel.length; 

    for(int i = 0; i < heightTemp; i++) 
    { 
     for(int j = 0; j < widthTemp; j++) 
     { 
      try 
      { 
       image = ImageIO.read(getFile()); 
      } 
      catch (Exception e) 
      { 
       e.printStackTrace(); 
      } 
      drawB(image); 
     } 
    } 
} 

public File getFile() 
{ 
    path = "images//1.jpg"; 
    File file = new File(path); 
    return file; 
} 

public void drawB(BufferedImage imgTemp) 
{ 
    image = imgTemp; 
    repaint(); 
} 

private void gameLoop() 
{ 
    long beginTime, timeTaken, timeLeft; 
    while (true) 
    { 
     repaint(); 

     beginTime = System.nanoTime(); 

     timeTaken = System.nanoTime() - beginTime; 
     timeLeft = (UPDATE_PERIOD - timeTaken)/1000000L; // in milliseconds 
     if (timeLeft < 10) timeLeft = 10; // set a minimum 
     try 
     { 
      Thread.sleep(timeLeft); 
     }  
     catch (InterruptedException ex) 
     { 
      // 
     } 
    } 
} 

// Refresh the display. Called back via repaint(), which invoke the paintComponent(). 
private void gameDraw(Graphics2D g2d) 
{ 
    g2d.drawImage(image, 0, 0, 15, 15, this); 
} 

public void gameKeyPressed(int keyCode) 
{ 
    // 
} 

public void gameKeyReleased(int keyCode) 
{ 
    // 
} 

public void gameKeyTyped(char keyChar) 
{ 
    // 
} 

class GameCanvas extends JPanel implements KeyListener 
{ 
    boolean paintAll; 
    int xPos, yPos; 
    Image img; 

    public GameCanvas() 
    { 
     setFocusable(true); 
     requestFocus(); 
     addKeyListener(this); 
    } 

    // Override paintComponent to do custom drawing. 
    // Called back by repaint()... sometimes? 
    @Override 
    public void paintComponent(Graphics g) 
    { 
     System.out.println("repainting"); 
     Graphics2D g2d = (Graphics2D)g; 

     // Draw the game objects 
     gameDraw(g2d); 
    } 


    // KeyEvent handlers 
    @Override 
    public void keyPressed(KeyEvent e) 
    { 
     gameKeyPressed(e.getKeyCode()); 
    } 

    @Override 
    public void keyReleased(KeyEvent e) 
    { 
     gameKeyReleased(e.getKeyCode()); 
    } 

    @Override 
    public void keyTyped(KeyEvent e) 
    { 
     gameKeyTyped(e.getKeyChar()); 
    } 
} 

// To start and re-start the game. 
public void gameStart() 
{ 
    // Create a new thread 
    Thread gameThread = new Thread() 
    { 
     // Override run() to provide the running behavior of this thread. 
     @Override 
     public void run() 
     { 
      gameLoop(); 
     } 
    }; 
    // Start the thread. start() calls run(), which in turn calls gameLoop(). 
    gameThread.start(); 
} 

// main 
public static void main(String[] args) 
{ 
    // Use the event dispatch thread to build the UI for thread-safety. 
    SwingUtilities.invokeLater(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      new GameMain(); 
     } 
    }); 
} 
} 
+2

希望這個關於[paintComponent不起作用,如果它的遞歸函數調用?](http://stackoverflow.com/q/10338163/1057230),將有一些你感興趣。和往常一樣,答案中給出的建議非常好,堅持不懈。 –

+0

另外不要忘記在重寫的paintComponent方法中調用super.paintConponent(g)。另請參見此處的固定時間步驟遊戲循環的一個很好的示例:http://stackoverflow.com/a/14001011/1133011也不會不必要地擴展JFrame –

回答

3

這是有道理的,是不是因爲初始化代碼初始化過程中響應:

public void dispArray() { 
    int tempLevel[][] = new int[][] { { 1, 1, 1, 1 }, { 6, 2, 2, 2 }, 
     { 3, 3, 3, 3 }, { 4, 4, 4, 4 }, { 4, 4, 4, 4 }, { 4, 4, 4, 4 }, 
     { 4, 4, 4, 4 }, { 4, 4, 4, 4 }, { 4, 4, 4, 4 } }; 
    int widthTemp = tempLevel[0].length; 
    int heightTemp = tempLevel.length; 
    for (int i = 0; i < heightTemp; i++) { 
    for (int j = 0; j < widthTemp; j++) { 
      try { 
       image = ImageIO.read(getFile()); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     drawB(image); 
    } 
    } 
} 

public File getFile() { 
    path = "images//1.jpg"; 
    File file = new File(path); 
    return file; 
} 

public void drawB(BufferedImage imgTemp) { 
    image = imgTemp; 
    repaint(); 
} 

包括圖像文件的閱讀,是所有被Swing事件線程上完成的,有些東西你永遠不應該做。

解決方法:不要這樣做。取而代之的是使用後臺線程,例如SwingWorker提供的後臺線程。欲瞭解更多信息,請閱讀Concurrency in Swing