废话少说,放码上来
public class MarioFrame extends JFrame {
public MarioFrame() {
this.initFrame();
}
public void initFrame() {
this.setTitle("Mario");
this.setSize(600, 480);
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
GamePanel gp = new GamePanel();
this.add(gp);
this.setJMenuBar(new Menu());
System.out.println(gp.getSize());
this.setVisible(true);
}
}
java.awt.Dimension[width=0,height=0]
窗体正常显示,但得到的JPanel大小为0.当然,调用getPreferredSize()结果也是一样。
为什么呢?
原因是 此方法的调用在窗体显示之前
在以上代码中,虽然成功给Frame窗体添加了JPanel面板,但是代码没有运行到
this.setVisible(true);
语句,窗体并没有显现,面板也就没有显现,此时面板的大小当然为0;
就算已经给JPanel设置了大小,由于没有显示的原因,getSize()方法还是不能得到面板的数据。
由此得到一个结论,getSize()和getPreferredSize()方法的执行,是从闪存中调用数据的。就算已经加载到了内存里面,在代码加载到闪存显示画面之前还是不能得到数据。
因此,只要把上面代码中的getSize()语句放到setVisible(true)语句之后,就能正常得到面板大小。
那么,问题来了,为什么getSize()能够在JPanel的paint()方法里得到JPanel的大小的?
比如下面的代码
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
public class GamePanel extends JPanel{
public static ArrayList pipeList = new ArrayList();
Background background = new Background(2, 0, 2);
Mario mario = new Mario(150, 0, 28, 34, 4);
MarioMoveListener mml = new MarioMoveListener(mario,this,background);
public GamePanel() {
this.addGamePanel();
}
public void addGamePanel(){
//设置焦点
this.setFocusable(true);
//添加监听
this.addKeyListener(mml);
//添加管道
this.addPipe();
//添加管道
}
public void paint(Graphics g) {
System.out.println(this.getSize());
//准备一张缓冲背景图片
BufferedImage bi = (BufferedImage) this.createImage(this.getWidth(),this.getHeight());
//获取缓冲图片画笔
Graphics g_buffer = bi.getGraphics();
//将要绘制的内容,绘制到缓冲图片上
g_buffer.drawImage(background.image.getImage(), background.x, 0,10292,(int)this.getSize().getHeight(), null);
g_buffer.drawImage(mario.image.getImage(), mario.x, (int)(this.getSize().getHeight() * 0.8),mario.width,mario.height, null);
for(int i = 0;i < pipeList.size();i++){
Pipe pipe = pipeList.get(i);
g_buffer.drawImage(pipe.image.getImage(), pipe.x, pipe.y, pipe.width, pipe.height, null);
}
//将缓冲图片绘制到窗体
g.drawImage(bi, 0, 0, null);
}
public void addPipe(){
for(int i = 0; i < 100; i++){
Random ran = new Random();
int speed = 4;
int height = 100;
int width = 40;
Pipe pipe = new Pipe(400 + 200 * i , 200,width,height,4);
pipeList.add(pipe);
}
}
}
此时运行代码就能在控制台打印JPanel的大小
原因就是在窗口显示之后,系统自动调用了一次paint方法进行重绘。此时就涉及到paint方法的调用时机。
一般javax.swing包里的组件大部分是轻量级组件,所以查API可知,JPanel是轻量级组件。(轻重量级组件的具体内容见博客下另一篇)
因此,JPanel面板显示之后,调用了一次paint方法,此时就能得到面板的大小了。
这也间接解释了 为什么必须把要绘制的内容放在paint方法内(直接画在面板上会在显示一次之后被调用的paint方法覆盖掉,显示结果就是 闪一下就消失)