JAVA图形编程Swing之——JPanel绘图
2015-07-04 19:38
519 查看
JAVA图形编程Swing之——JPanel绘图
一直搞不清怎么在JPanel中绘2D图像,主要是不知怎样得到Graphics类的对像来画图,今天查了查资料,测试N种方法,终于搞明白。下面做一个测试总结。
一、自定义一个类,继承JPanel,直接重写它的paint方法。
二、图像缓冲
第二种方法就是使用Image和BufferImage技术,预先在一个图形缓冲中绘好要显示的内容,然后在paint方法中,一次性的把图形缓冲刷新到JPanel里肌,这种方法涉及到AWT中的Image和BufferImage,前者是一个接口,后者是一个可以实例化的类。其实,JPanel也是继承自AWT的Component类,该类有一个方法:Image createImage(int width, int height) ,这个方法也常在继承自JPanel的类中用于创建一幅用于双缓冲的、可在屏幕外绘制的图像。
实现方法一:
实现方法二:
总结:在绘制2D图形和实现动画的效果时,要用到AWT中的绘图技术和缓冲技术,如果只是简单的绘图,那么自定义Panel类,重写Paint方法,把要绘图代码放到paint方法中,由系统自动调用paint方法即可。
要实现动画效果则就要定时的调用repaint方法,repaint方法则会调用paint方法实现Panel重绘。
JPanel在什么情况下会被重绘呢?
1. 在repaint方法被显式的调用时。
2. 在窗口最小化然后又被显示时。
3. 在窗口被拉伸时。
一直搞不清怎么在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设计模式之单例模式k
- JAVA常用类之——System和Runtime
- Java源码---java.util.Arrays
- JAVA集合之——HashSet和LinkedSet
- java线程同步
- 冒泡排序-直接选择排序-直接插入排序-希尔排序-java实现
- ueditor1.4.3 springmvc图片上传
- eclipse 遇到 ADB server didn't ACK
- 2015070411 - EffactiveJava笔记 - 第61条 抛出与抽象对应的异常(3)
- SpringMVC异常处理
- java学习10--循环结构while、do while
- 基于spring4 websocket的简易聊天室
- 2015070410 - EffactiveJava笔记 - 第61条 抛出与抽象对应的异常(2)
- 一个不错的spring 学习博客
- Spring 标签解析——<AOP>
- Java移位运算符
- Java值传递与引用传递
- 2015070409 - EffactiveJava笔记 - 第61条 抛出与抽象对应的异常(1)
- Spring MVC的生命周期
- java 学习List 的 add 与set差分法