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

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

http://blog.csdn.net/fanwenjieok/article/details/46757139

原创 2015年07月04日 19:38:11
JAVA图形编程Swing之——JPanel绘图
 
    一直搞不清怎么在JPanel中绘2D图像,主要是不知怎样得到Graphics类的对像来画图,今天查了查资料,测试N种方法,终于搞明白。下面做一个测试总结。
 
     一、自定义一个类,继承JPanel,直接重写它的paint方法。
[java] view plain copy
 
  1. /** 
  2.  * 定义一个继承自JPanel的类,重写它的paint方法 * 
  3.  */  
  4. class MyPanel extends JPanel  
  5. {  
  6.     private int x = 200;  
  7.     private int y = 200;  
  8.       
  9.     public void display()  
  10.     {  
  11.         x ++;  
  12.         y ++;  
  13.           
  14.         //重绘JPanel  
  15.         this.repaint();  
  16.     }  
  17.       
  18.     /** 
  19.      * repaint方法会调用paint方法,并自动获得Graphics对像 
  20.      * 然后可以用该对像进行2D画图 
  21.      * 注:该方法是重写了JPanel的paint方法 
  22.      */  
  23.     public void paint(Graphics g)  
  24.     {  
  25.         //调用的super.paint(g),让父类做一些事前的工作,如刷新屏幕  
  26.         super.paint(g);   
  27.         Graphics2D g2d = (Graphics2D)g;  
  28.           
  29.         g2d.setColor(Color.RED);//设置画图的颜色  
  30.         g2d.fill3DRect(x, y, 100, 100, true);//填充一个矩形         
  31.     }  
  32. }  
  33.   
  34. public class PanelTest  
  35. {  
  36.     public static void main(String[] args)  
  37.     {  
  38.         JFrame  jf = new JFrame();  
  39.         MyPanel jp = new MyPanel();  
  40.           
  41.         jf.setBounds(200, 200, 500, 500);  
  42.         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  43.         jf.add(jp);  
  44.         jf.setVisible(true);  
  45.           
  46.         while(true)  
  47.         {  
  48.             //不停的重绘JPanel,实现动画的效果  
  49.             jp.display();  
  50.               
  51.             try  
  52.             {  
  53.                 Thread.sleep(300);  
  54.             }  
  55.             catch (InterruptedException e)  
  56.             {  
  57.                 e.printStackTrace();  
  58.             }  
  59.         }  
  60.     }  
  61. }  
    然而,上面的方法不总是有效的,在开始的时候,如果为得到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的类中用于创建一幅用于双缓冲的、可在屏幕外绘制的图像。
    实现方法一:
[java] view plain copy
 
  1. /** 
  2.  * 定义一个继承自JPanel的类,重写它的paint方法 * 
  3.  */  
  4. class MyPanel1 extends JPanel  
  5. {  
  6.     private int x = 200;  
  7.     private int y = 200;  
  8.     private Image image;    //图像缓冲  
  9.     private Graphics og;  
  10.       
  11.     public void display()  
  12.     {  
  13.         x ++;  
  14.         y ++;  
  15.           
  16.         if(og == null)  
  17.         {  
  18.             //JPanel继承自Component类,可以使用它的方法createImage创建一幅和JPanel大小相同的图形缓冲  
  19.             //然后用它Image接口的方法获得绘图对像  
  20.             image = this.createImage(this.getWidth(),this.getHeight());  
  21.             if(image != null)og = image.getGraphics();  
  22.         }  
  23.           
  24.         if(og != null)  
  25.         {  
  26.             //调用的super.paint(g),让父类做一些事前的工作,如刷新屏幕  
  27.             super.paint(og);      
  28.                           
  29.             og.setColor(Color.RED);             //设置画图的颜色  
  30.             og.fill3DRect(x, y, 100, 100, true);//绘图                  
  31.             //this.paint(this.getGraphics());  
  32.         }  
  33.         //重绘JPanel  
  34.         this.repaint();  
  35.     }  
  36.       
  37.     /** 
  38.      * repaint方法会调用paint方法,并自动获得Graphics对像 
  39.      * 然后可以用该对像进行2D画图 
  40.      * 注:该方法是重写了JPanel的paint方法 
  41.      */  
  42.     public void paint(Graphics g)  
  43.     {  
  44.         g.drawImage(image, 0, 0, this);   
  45.     }  
  46. }  
  47.   
  48. public class PanelTest2  
  49. {  
  50.     public static void main(String[] args)  
  51.     {  
  52.         JFrame  jf = new JFrame();  
  53.         MyPanel1 jp = new MyPanel1();  
  54.           
  55.         jf.setBounds(200, 200, 500, 500);  
  56.         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  57.         jf.add(jp);  
  58.         jf.setVisible(true);  
  59.           
  60.         while(true)  
  61.         {  
  62.             //不停的重绘JPanel,实现动画的效果  
  63.             jp.display();  
  64.               
  65.             try  
  66.             {  
  67.                 Thread.sleep(300);  
  68.             }  
  69.             catch (InterruptedException e)  
  70.             {  
  71.                 e.printStackTrace();  
  72.             }  
  73.         }  
  74.     }  
  75. }  
    上面的方法是在自定义Panel的内部实现了Image对像的创建,绘图,刷新,然后有时候程序的模块化划分方法并不是这样,所以还可以在该类的外部创建一个Image对像,并完成绘图,将该对像的引用传递给自定义Panel的绘图方法,也可以完成绘图,并且,我觉得这样更灵活。
    
    实现方法二:
[java] view plain copy
 
  1. class MyPanel3 extends JPanel  
  2. {  
  3.     private int x = 200;  
  4.     private int y = 200;  
  5.       
  6.     private Graphics g;  
  7.     private Image im ;  
  8.       
  9.     //构造方法,获得外部Image对像的引用  
  10.     public MyPanel3(Image im)  
  11.     {  
  12.         if(im != null)  
  13.         {  
  14.             this.im = im;  
  15.             g = im.getGraphics();  
  16.         }  
  17.     }  
  18.       
  19.     public void display()  
  20.     {  
  21.         x ++;  
  22.         y ++;             
  23.         if(g != null)  
  24.         {  
  25.             //调用的super.paint(g),让父类做一些事前的工作,如刷新屏幕  
  26.             super.paint(g);  
  27.             g.setColor(Color.RED);              //设置画图的颜色  
  28.             g.fill3DRect(x, y, 100, 100, true); //填充一个矩形          
  29.             //更新缓图  
  30.             this.repaint();  
  31.         }  
  32.     }  
  33.       
  34.     /** 
  35.      * repaint方法会调用paint方法,并自动获得Graphics对像 
  36.      * 然后可以用该对像进行2D画图 
  37.      * 注:该方法是重写了JPanel的paint方法 
  38.      */  
  39.     public void paint(Graphics g)  
  40.     {  
  41.         g.drawImage(im, 0, 0, this);  
  42.     }  
  43. }  
  44.   
  45. public class PanelTEST4  
  46. {  
  47.     public static void main(String[] args)  
  48.     {  
  49.         //在自定义Panel的外部定义一个Image绘图区  
  50.         Image im = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);  
  51.           
  52.         JFrame   jf = new JFrame();  
  53.         //通过构造方法将缓冲缓冲区对像的引用传给自定义Panel  
  54.         MyPanel3 jp = new MyPanel3(im);  
  55.           
  56.         jf.setBounds(200,200,500, 500);  
  57.         jp.setSize(300, 300);  
  58.         jf.add(jp);  
  59.         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);            
  60.         jf.setVisible(true);  
  61.       
  62.         while(true)  
  63.         {  
  64.             jp.display();  
  65.               
  66.             try  
  67.             {  
  68.                 Thread.sleep(300);  
  69.             }   
  70.             catch (InterruptedException e)  
  71.             {  
  72.                 e.printStackTrace();  
  73.             }  
  74.         }         
  75.     }  
  76. }  

    总结:在绘制2D图形和实现动画的效果时,要用到AWT中的绘图技术和缓冲技术,如果只是简单的绘图,那么自定义Panel类,重写Paint方法,把要绘图代码放到paint方法中,由系统自动调用paint方法即可。
    要实现动画效果则就要定时的调用repaint方法,repaint方法则会调用paint方法实现Panel重绘。
 
    JPanel在什么情况下会被重绘呢?
    1. 在repaint方法被显式的调用时。
    2. 在窗口最小化然后又被显示时。
    3. 在窗口被拉伸时。
 
posted @ 2018-01-07 13:01  sky20080101  阅读(1696)  评论(0)    收藏  举报