Java JPanel的getSize()方法 有时候得到的结果为0 的原因(涉及语句顺序、paint方法的调用)

废话少说,放码上来

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);
	}
}

在上面窗体类的代码中,给窗体对象添加了一个JPanel类的对象gp,之后调用getSize()方法并打印到控制台。添加了面板对象,之后得到它的大小并且打印,看似没错,然而实际的运行结果是 

 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是轻量级组件。(轻重量级组件的具体内容见博客下另一篇)

Java JPanel的getSize()方法 有时候得到的结果为0 的原因(涉及语句顺序、paint方法的调用)_第1张图片



轻量级组件处理系统触发的请求有两种方法


一种是系统触发的请求,由本地系统发起,例如 轻量级组件的重量级祖先组件第一次显示,将会调用paint()方法;

一种是系统触发的请求,由轻量级框架发起,例如轻量级组件大小被调整,将会调用update(),这个方法默认调用paint()方法。


因此,JPanel面板显示之后,调用了一次paint方法,此时就能得到面板的大小了。


这也间接解释了 为什么必须把要绘制的内容放在paint方法内(直接画在面板上会在显示一次之后被调用的paint方法覆盖掉,显示结果就是 闪一下就消失)





你可能感兴趣的:(Java)