调用pack()后,JPanel getWidth()返回Zero

时间:2013-06-24 23:51:19

标签: java swing jframe jpanel

我相信我的代码会描述我写的内容,但问题是,当我运行它时,我得到了臭名昭着的“线程中的异常”Animator“java.lang.IllegalArgumentException:Width(0)and height(0 )不能是< = 0“错误。我已经搜索了答案,但尚未找到原因。

package com.shparki.TowerDefense;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable{

//==================== PROGRAM VARIABLES ====================//
    private static final int WIDTH = 300;
    private static final int HEIGHT = WIDTH / 16 * 9;
    private static final int SCALE = 4;

    private static final int TARGET_FPS = 45;
    private static final int PERIOD = 1000 / TARGET_FPS;

    private boolean debug = true;
    private volatile boolean running = false;
    private volatile boolean gameOver = false;
    private volatile boolean paused = false;

    private Thread animator;
    private TowerDefense frame;

    private double currentFPS;


//==================== PROGRAM METHODS ====================//
    public GamePanel(TowerDefense td){
        frame = td;

        setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));

        setVisible(true);
    }
    public void addNotify(){
        super.addNotify();
        startGame();
    }
    public void startGame(){
        if (!running && animator == null){
            animator = new Thread(this, "Animator");
            animator.start();
        }
    }
    public void stopGame(){
        running = false;
    }
    public void run(){
        running = true;
        Long beforeTime, timeDiff, sleepTime;

        while(running){
            beforeTime = System.currentTimeMillis();

            update();
            render();
            paintScreen();

            timeDiff = System.currentTimeMillis() - beforeTime;
            sleepTime = PERIOD - timeDiff;
            if (sleepTime <= 0){
                sleepTime = 5L;
            }

            currentFPS = (1000 / ( timeDiff + sleepTime ));

            try{
                Thread.sleep(sleepTime);
            } catch (InterruptedException ex) { ex.printStackTrace(); }
        }
        System.exit(0);
    }

//==================== DRAWING METHODS ====================//
    private Graphics dbg;
    private Image dbImage;

    public void paintComponenet(Graphics g){
        super.paintComponent(g);
        if (dbImage != null){
            g.drawImage(dbImage, 0, 0, null);
        }
    }
    public void paintScreen(){
        Graphics g;
        try{
            g = this.getGraphics();
            if (g != null & dbImage != null){
                g.drawImage(dbImage, 0, 0, null);
            }
            Toolkit.getDefaultToolkit().sync();
            g.dispose();
        } catch (Exception ex) { System.out.println("Graphics context error: " + ex); }
    }
    public void doubleBuffer(){
        if (dbImage == null){
            dbImage = createImage(getWidth(), getHeight());
            if (dbImage == null){
                System.out.println("dbImage is null");
                return;
            } else {
                dbg = dbImage.getGraphics();
            }
        }
    }

//==================== UPDATE METHODS ====================//
    public void update(){

    }


//==================== RENDER METHODS ====================//
    public void render(){
        doubleBuffer();

        Graphics2D g2d = (Graphics2D) dbg;

        g2d.setColor(Color.BLACK);
        g2d.fillRect(0, 0, getWidth(), getHeight());
    }

}

这是我的框架类:

package com.shparki.TowerDefense;

import java.awt.BorderLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;

public class TowerDefense extends JFrame implements WindowListener{

    public TowerDefense(String name){
        super(name);
        setResizable(false);

        setLayout(new BorderLayout());
        add(new GamePanel(this), BorderLayout.CENTER);
        pack();

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);

    }


    public void windowActivated(WindowEvent arg0) {  }
    public void windowClosed(WindowEvent arg0) {  }
    public void windowClosing(WindowEvent arg0) {  }
    public void windowDeactivated(WindowEvent arg0) {  }
    public void windowDeiconified(WindowEvent arg0) {  }
    public void windowIconified(WindowEvent arg0) {  }
    public void windowOpened(WindowEvent arg0) {  }

    public static void main(String[] args){
        new TowerDefense("Tower Defense Game");
    }

}

1 个答案:

答案 0 :(得分:1)

JFrame尚未打包,然后在GamePanel

中请求高度和宽度
dbImage = createImage(getWidth(), getHeight());

0x0生成JPanel维度。

原因是,一旦为组件设置了父组件,Swing几乎立即调用addNotify(其中startGame所在的位置)。

您可以在调用pack后显式调用startGame

add(gamePanel, BorderLayout.CENTER);
pack();
gamePanel.startGame();