JAVA图形编程Swing之——JPanel绘图

JAVA图形编程Swing之——JPanel绘图

    一直搞不清怎么在JPanel中绘2D图像,主要是不知怎样得到Graphics类的对像来画图,今天查了查资料,测试N种方法,终于搞明白。下面做一个测试总结。

     一、自定义一个类,继承JPanel,直接重写它的paint方法。
/**
 * 定义一个继承自JPanel的类,重写它的paint方法 *
 */
class MyPanel extends JPanel
{
	private int x = 200;
	private int y = 200;
	
	public void display()
	{
		x ++;
		y ++;
		
		//重绘JPanel
		this.repaint();
	}
	
	/**
	 * repaint方法会调用paint方法,并自动获得Graphics对像
	 * 然后可以用该对像进行2D画图
	 * 注:该方法是重写了JPanel的paint方法
	 */
	public void paint(Graphics g)
	{
		//调用的super.paint(g),让父类做一些事前的工作,如刷新屏幕
		super.paint(g);	
		Graphics2D g2d = (Graphics2D)g;
		
		g2d.setColor(Color.RED);//设置画图的颜色
		g2d.fill3DRect(x, y, 100, 100, true);//填充一个矩形		
	}
}

public class PanelTest
{
	public static void main(String[] args)
	{
		JFrame  jf = new JFrame();
		MyPanel jp = new MyPanel();
		
		jf.setBounds(200, 200, 500, 500);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.add(jp);
		jf.setVisible(true);
		
		while(true)
		{
			//不停的重绘JPanel,实现动画的效果
			jp.display();
			
			try
			{
				Thread.sleep(300);
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
	}
}
    然而,上面的方法不总是有效的,在开始的时候,如果为得到Graphics对像,那么g就为null,而下面直接使用g,就会产生空指针异常 。稳妥的办法是在使用g之前要加上判断 if(g != null) { ........}

    二、图像缓冲

    第二种方法就是使用Image和BufferImage技术,预先在一个图形缓冲中绘好要显示的内容,然后在paint方法中,一次性的把图形缓冲刷新到JPanel里肌,这种方法涉及到AWT中的Image和BufferImage,前者是一个接口,后者是一个可以实例化的类。其实,JPanel也是继承自AWT的Component类,该类有一个方法:Image createImage(int width, int height) ,这个方法也常在继承自JPanel的类中用于创建一幅用于双缓冲的、可在屏幕外绘制的图像。
    实现方法一:
/**
 * 定义一个继承自JPanel的类,重写它的paint方法 *
 */
class MyPanel1 extends JPanel
{
	private int x = 200;
	private int y = 200;
	private Image image;	//图像缓冲
	private Graphics og;
	
	public void display()
	{
		x ++;
		y ++;
		
		if(og == null)
		{
			//JPanel继承自Component类,可以使用它的方法createImage创建一幅和JPanel大小相同的图形缓冲
			//然后用它Image接口的方法获得绘图对像
			image = this.createImage(this.getWidth(),this.getHeight());
			if(image != null)og = image.getGraphics();
		}
		
		if(og != null)
		{
			//调用的super.paint(g),让父类做一些事前的工作,如刷新屏幕
			super.paint(og);	
						
			og.setColor(Color.RED);				//设置画图的颜色
			og.fill3DRect(x, y, 100, 100, true);//绘图				
			//this.paint(this.getGraphics());
		}
		//重绘JPanel
		this.repaint();
	}
	
	/**
	 * repaint方法会调用paint方法,并自动获得Graphics对像
	 * 然后可以用该对像进行2D画图
	 * 注:该方法是重写了JPanel的paint方法
	 */
	public void paint(Graphics g)
	{
		g.drawImage(image, 0, 0, this);	
	}
}

public class PanelTest2
{
	public static void main(String[] args)
	{
		JFrame  jf = new JFrame();
		MyPanel1 jp = new MyPanel1();
		
		jf.setBounds(200, 200, 500, 500);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.add(jp);
		jf.setVisible(true);
		
		while(true)
		{
			//不停的重绘JPanel,实现动画的效果
			jp.display();
			
			try
			{
				Thread.sleep(300);
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
	}
}
    上面的方法是在自定义Panel的内部实现了Image对像的创建,绘图,刷新,然后有时候程序的模块化划分方法并不是这样,所以还可以在该类的外部创建一个Image对像,并完成绘图,将该对像的引用传递给自定义Panel的绘图方法,也可以完成绘图,并且,我觉得这样更灵活。
    
    实现方法二:
class MyPanel3 extends JPanel
{
	private int x = 200;
	private int y = 200;
	
	private Graphics g;
	private Image im ;
	
	//构造方法,获得外部Image对像的引用
	public MyPanel3(Image im)
	{
		if(im != null)
		{
			this.im = im;
			g = im.getGraphics();
		}
	}
	
	public void display()
	{
		x ++;
		y ++;			
		if(g != null)
		{
			//调用的super.paint(g),让父类做一些事前的工作,如刷新屏幕
			super.paint(g);
			g.setColor(Color.RED);				//设置画图的颜色
			g.fill3DRect(x, y, 100, 100, true);	//填充一个矩形		
			//更新缓图
			this.repaint();
		}
	}
	
	/**
	 * repaint方法会调用paint方法,并自动获得Graphics对像
	 * 然后可以用该对像进行2D画图
	 * 注:该方法是重写了JPanel的paint方法
	 */
	public void paint(Graphics g)
	{
		g.drawImage(im, 0, 0, this);
	}
}

public class PanelTEST4
{
	public static void main(String[] args)
	{
		//在自定义Panel的外部定义一个Image绘图区
		Image im = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
		
		JFrame   jf = new JFrame();
		//通过构造方法将缓冲缓冲区对像的引用传给自定义Panel
		MyPanel3 jp = new MyPanel3(im);
		
		jf.setBounds(200,200,500, 500);
		jp.setSize(300, 300);
		jf.add(jp);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);			
		jf.setVisible(true);
	
		while(true)
		{
			jp.display();
			
			try
			{
				Thread.sleep(300);
			} 
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}		
	}
}

    总结:在绘制2D图形和实现动画的效果时,要用到AWT中的绘图技术和缓冲技术,如果只是简单的绘图,那么自定义Panel类,重写Paint方法,把要绘图代码放到paint方法中,由系统自动调用paint方法即可。
    要实现动画效果则就要定时的调用repaint方法,repaint方法则会调用paint方法实现Panel重绘。

    JPanel在什么情况下会被重绘呢?
    1. 在repaint方法被显式的调用时。
    2. 在窗口最小化然后又被显示时。
    3. 在窗口被拉伸时。

你可能感兴趣的:(JAVA,SE基础)