2014-12-21 42 views
0

我有一個小的,簡單的程序,我已經開始,並有一個奇怪的錯誤,我一直無法找出或找到在線原因。JPanel不會畫出圖像,直到鼠標點擊

我現在所有的程序都是建立一個JFrame,建立一個JPanel,並從一個線程在JPanel上繪製一個圖像。問題是,除非我單擊框架,左鍵單擊,右鍵單擊,或者使用鼠標滾輪單擊鼠標滾輪才能顯示圖像,否則圖像不會顯示,但調整框架大小並不會顯示圖像。我已經在面板和框架上嘗試了validate(),並且我嘗試了在線程調用的代碼中放入repaint(),但當repaint()在代碼中時圖像會閃爍。

我在實際繪製圖像的代碼中放置了打印語句,但是直到單擊框架後,該語句才顯示出來。我已經用調試器走過了,儘管如此,代碼似乎正在被調用。如果我在主線程的update()函數中調用的代碼中的任何位置放置打印語句,則圖像將正確顯示而不必點擊。

這是我的代碼,任何建議,將不勝感激:

的幀

public class GameFrame extends JFrame{ 

    int w = 1300; 
    int h = 740; 

    public GameFrame() { 

    this.setSize(w, h); 
    setTitle("Frame"); 

    GamePanel panel = new GamePanel(w, h); 
    this.add(panel); 
    this.setVisible(true); 
    this.setDefaultCloseOperation(EXIT_ON_CLOSE); 
    } 

    public static void main(String[] args) { 
    GameFrame gameFrame = new GameFrame(); 
    } 
} 

小組

public class GamePanel extends JPanel implements Runnable{ 

//core classes 
GameRenderer renderer; 
GameManager manager; 
GameLoader loader; 

//graphics stuff 
private Graphics dbg; 
private Image dbImage = null; 
private int panelWidth; 
private int panelHeight; 

//game updating stuff 
Thread animator; 
boolean running; 

public GamePanel(int w, int h) { 
    this.setSize(w, h); 
    this.setVisible(true); 
    this.setFocusable(true); 
    this.panelWidth = w; 
    this.panelHeight = h; 

    renderer = new GameRenderer(); 
    manager = new GameManager(); 
    loader = new GameLoader(); 

    startGame(); 
} 

private void startGame() { 
    animator = new Thread(this, "Animator"); 
    animator.start(); 
    running = true; 
} 

public void run() { 
    while(running) { 
     gameAction(); 
    } 
} 

//everything that needs to be updated continuously 
private void gameAction() { 
    //updateGame(); // Need code here to update everything 
    gameRender(); // Draw to the double buffer. 
    paintScreen(); // Draw double buffer to screen. 
} 

/** 
* Draws the game image to the buffer. 
* 
*/ 
private void gameRender() { 
    if(dbImage == null) { 
     dbImage = createImage(this.panelWidth, this.panelHeight); 
     return; 
    } 
    dbg = dbImage.getGraphics(); 
    renderer.draw((Graphics2D) dbg, panelWidth, panelHeight); 
} 

/** 
* Draws the game image to the screen by drawing the buffer. 
*/ 
private void paintScreen() { 
    Graphics g; 
    try { 
     g = this.getGraphics(); 
     if ((g != null) && (dbImage != null)) { 
      g.drawImage(dbImage, 0, 0, null); 
      g.dispose(); 
     } 
    } catch (Exception e) { System.out.println("Graphics context error: " + e); } 
} 

} 

圖像渲染器

public class GameRenderer { 

ImageManipulator im = new ImageManipulator(); 

/** 
* Actually draw everything that needs to be drawn 
* Layering also happens here 
*/ 
public void draw(Graphics2D g,int screenWidth, int screenHeight) { 
    BufferedImage tileImg = im.loadImage("Images/tile.png"); 
    Tile tile = new Tile(tileImg, 30, 30); 
    tile.draw(g); 
} 

} 

類與圖像I試試吧繪製

public class Tile { 

BufferedImage tileImg; 
//x and y values based on tile grid - z based on height up 
int tileX; 
int tileY; 
int tileZ; 
//actual coordinate of top left corner of tile *image* 
int pixelX; 
int pixelY; 

public Tile(BufferedImage img, int pixelX, int pixelY) { 
    this.pixelX = pixelX; 
    this.pixelY = pixelY; 
    this.tileImg = img; 
} 

public void draw(Graphics g) { 
    g.drawImage(tileImg, pixelX, pixelY, null); 
} 

} 

再次,任何建議或想法都會有所幫助。我對可能造成這種情況的想法一無所知。 另外,是否有人知道爲什麼這可能與包含打印語句但不是沒有打印語句?

+0

我不是圖形如何在引擎蓋下揮杆管理方面的專家,但我習慣調用'repaint()'。 (對於你的問題的一個快速解決方法是添加:'更新(g)'到paintScreen方法)。 –

+0

這有助於縮小它的範圍。如果我將update(g)放在這個if語句中,我會得到相同的結果:'if((g!= null)&&(dbImage!= null))'。如果我把它放在這行後面'g = this.getGraphics();'我得到了一些空指針異常(這是有道理的),但它顯示正確。我猜想,如果陳述導致它不呈現的東西。 –

+2

不,使用'getGraphics()'方法不會在完成後將圖形放在屏幕上,AFAIK。 'repaint()'是執行此操作的首選方法。 –

回答

3

您誤會了如何在Swing組件中進行自定義繪畫。撥打this.getGraphics()是不正確的。繪製Swing組件的正確方法是覆蓋其paintComponent方法。注意,在方法必須呼叫super.paintComponent的第一行:

@Override 
protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    if (dbImage != null) { 
     g.drawImage(dbImage, 0, 0, this); 
    } 
} 

另外請注意,你不能擅自處理對象的圖形,因爲你沒有創建它,它是Swing的控制之下,而不是你。

有關詳細信息,請參見Painting in AWT and Swing教程。

當你想讓遊戲重畫時,只需調用面板的repaint方法即可。因此,你的gameAction方法應該用repaint()來替換paintScreen(),它會自動調用你面板的paintComponent方法(和其他一些方法;正如該教程所解釋的,繪畫不是一件簡單的事情)。

您需要在run()方法中的循環內放置一個短暫的sleep調用。如果您嘗試不斷更新並重新繪製遊戲,則該程序將沒有時間來實際繪製任何內容。舉例來說,如果你想在遊戲更新每秒5次(即每200毫秒):

try { 
    while (running) { 
     gameAction(); 
     Thread.sleep(200); 
    } 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 
0

我有兩個猜測。第一個是GamePanel中的startGame方法。放行「running = true;」在你的線程中調用「start()」之前。

如果不行,試試這個在您的run()方法中的GamePanel:

public void run() { gameAction(); } 

如果它呈現,那麼問題是while循環。

+0

嗯,它看起來不像它們中的任何一個。我甚至在運行函數中嘗試了'if(true)gameAction();'來驗證。 –