java纯新手想提问下关于paint()的问题

各位大大好,我是跟着视频自学的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方法调用完成的最后时刻启动的一个线程,事件分发。