各位大大好,我是跟着视频自学的java纯新手,在写的代码中出现了一些问题想请教一下 代码如下
import java.awt.Graphics;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
public class myFrame extends JFrame implements KeyListener{
private ListallBG=new ArrayList();
private background nowBG=null;
public static void main(String args[]){
new myFrame();
}
public myFrame(){
this.setTitle("马里奥游戏程序");
this.setSize(900,600);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setResizable(false);
//初始化场景之前要初始化全部图片
StaticValue.init();
//创建全部场景
for(int i=1;i<=3;i++){
this.allBG.add(new background(i,i==3?true:false));
}
//将第一个场景设置为当前场景
this.nowBG=this.allBG.get(0);
//测试nowBG是否为空,非空
if(nowBG==null){
System.out.println("is null");
}
else
System.out.println("not null");
this.repaint();
this.addKeyListener(this);
}
public void paint (Graphics g){
//建立临时缓冲图片
BufferedImage image=new BufferedImage(900,600,BufferedImage.TYPE_3BYTE_BGR);
Graphics g2=image.getGraphics();
if (nowBG!=null){
g2.drawImage(this.nowBG.getBgImage(),0,0,this);
System.out.println("is not null");
}
else
System.out.println("is null");
//把图片绘制到窗体
g.drawImage(image,0,0,this);
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
char a=e.getKeyChar();
int b=e.getKeyCode();
System.out.println(a+" "+b);
// TODO Auto-generated method stub
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
显示出来的结果是
is null
not null
is not null
我想问一下paint()在什么时候被调用的?为什么被调用了两次?为什么paint()第一次被调用的时候nowBG没有被初始化。然后就是运行的时候如果去掉paint()里的if else判断直接调用g2.drawImage(this.nowBG.getBgImage(),0,0,this)会出现java.lang.NullPointerException这该如何解决
首先一个概念,paint就是绘制的意思
.
你所看到的窗体(Window)
是个容器(Container)
,容器中有很多东西,比如你的JFrame
.
注意
看下面这段代码:
this.setVisible(true);
this.setResizable(false);
//初始化场景之前要初始化全部图片
StaticValue.init();
//创建全部场景
for(int i=1;i<=3;i++){
this.allBG.add(new background(i,i==3?true:false));
}
//将第一个场景设置为当前场景
this.nowBG=this.allBG.get(0);
//测试nowBG是否为空,非空
if(nowBG==null){
System.out.println("is null");
}
this.setVisible(true);
这行代码先执行,而this.nowBG=this.allBG.get(0);
后执行。
setVisible(true)
的意思是在屏幕上显示.
这句话会在引起它的父容器(包括爷爷容器、祖先容器)中的visible
字段的判断.
而这个visible
联合其它的字段来判断是否需要重新绘制repaint
。
那么,在你的this.allBG.add(new background(i,i==3?true:false));
执行前,
由于事先调用了setVisible
,所以你的paint
被调用,
这会导致你的问题直接调用g2.drawImage(this.nowBG.getBgImage(),0,0,this)会出现java.lang.NullPointerException这该如何解决
.
paint
方法调用的时机主要看容器中是否有脏的组件(dirtyComponents),这里的脏
指的是否需要重新绘制组件。
所以当任何一个事件,比如最小化
、最大化(可能)
、重新调整窗体(或父容器)大小
,图片的bits数(图片是二进制数据)来了一批就paint一批等等,都会引起是否重绘(repaint
)的判定,那么如果需要repaint
就可能调用'paint'.
你懂了吗??请采纳!!
1、我想问一下paint()在什么时候被调用的?【在你this.setVisible(true);界面可见的时候paint就开始执行了】
2、为什么被调用了两次?【paint一直在不断执行,不是1次2次的问题】
3、为什么paint()第一次被调用的时候nowBG没有被初始化。
【在你setvisible后,paint开始执行,而下面
StaticValue.init();
//创建全部场景
for(int i=1;i<=3;i++){
this.allBG.add(new background(i,i==3?true:false));
}
这几行代码执行需要时间,因此执行paint的时候this.nowBG还没有赋值
】
4、然后就是运行的时候如果去掉paint()里的if else判断直接调用g2.drawImage(this.nowBG.getBgImage(),0,0,this)会出现java.lang.NullPointerException这该如何解决【原因第三点已经说了,可以把初始化放到setvisible(true)这行代码前执行
//初始化场景之前要初始化全部图片
StaticValue.init();
//创建全部场景
for(int i=1;i<=3;i++){
this.allBG.add(new background(i,i==3?true:false));
}
//将第一个场景设置为当前场景
this.nowBG=this.allBG.get(0);
this.setTitle("马里奥游戏程序");
this.setSize(900,600);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setResizable(false);
请采纳!
当你的JFrame实例化时,顺序会是这样:组件
->容器->窗体->框体(JFrame).
这里面的逻辑比较复杂,但可以给你说几点:setVisible
方法用来设置元素是否被绘制到屏幕上.
在这个方法调用时,组件
的visible
变量已经初始化为true,这是个很重要的字段,和其它方法一起协同控制是否需要进行重绘操作。
当需要重绘时,你的paint
就可能会被调用.
你所看到的窗体,无论上面有字还是有图,都不全然是静态的。
主线程组(main)的很多线程协同工作,主要的几个:
1.main线程执行你的JFrame实例化,同时引发组件实例化,过程中,组件会调用java最底层的GUI并启动一个GC线程.
2.Java2D Disposer线程用来扫描是否有操作系统资源需要释放回收.
3.DestroyJavaVM线程用来在main线程执行完毕后销毁JVM虚拟机(你java运行的基础).
4.AWT-XAWT一个控制本地绘图资源和事件的线程,你绘图就靠这个
5.AWT-EventQueue在你的setVisible方法调用完成的最后时刻启动的一个线程,事件分发。