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

来源:互联网 发布:淘宝ulike脱毛仪骗局 编辑:程序博客网 时间:2024/05/18 11:26

废话少说,放码上来

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());<span style="color:#ff0000;">System.out.println(gp.getSize());</span>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<Pipe> pipeList = new ArrayList<Pipe>();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) {<span style="color:#ff0000;">System.out.println(this.getSize());</span>//准备一张缓冲背景图片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是轻量级组件。(轻重量级组件的具体内容见博客下另一篇)




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


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

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


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


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





0 0
原创粉丝点击