Draw类也要做一些修改,为按钮和面板添加监听:
1 package Cbs; 2 3 import java.awt.Color; 4 import java.awt.Dimension; 5 import java.awt.FlowLayout; 6 import java.awt.Graphics; 7 import java.awt.GridLayout; 8 9 import javax.swing.JButton; 10 import javax.swing.JFrame; 11 import javax.swing.JPanel; 12 13 /** 14 * Draw类,用于界面的初始化 15 * @author CBS 16 */ 17 @SuppressWarnings("serial") 18 public class Draw extends JFrame { 19 private DrawListener dl; 20 private Graphics g; 21 // 界面初始化方法 22 public void showUI() { 23 setTitle("画图");//窗体名称 24 setSize(1200, 900);//窗体大小 25 setDefaultCloseOperation(3); 26 setLocationRelativeTo(null);//窗体居中 27 //流式布局左对齐 28 FlowLayout layout = new FlowLayout(FlowLayout.LEFT); 29 setLayout(layout);//窗体使用流式布局管理器 30 this.setResizable(false);//窗体大小不变 31 32 //使用数组保存按钮名 33 String buttonName[] = { "画直线", "画椭圆", "画曲线", "多边形", 34 "橡皮擦", "拖动线","三角形", "画球形", "笔刷", "喷枪", 35 "色子", "立体矩形", "立体圆", "立体三角","迭代分形", 36 "现代分形", "枫叶", "画树", "mandelbrot集", "L-System", 37 "迭代画线","迭代三角形", "谢尔宾斯基地毯", "画字符", "清空", 38 "吸管" ,"矩形","五角星","多线","字符"}; 39 //用于保存图形按钮,使用网格布局 40 JPanel jp1=new JPanel(new GridLayout(15, 2,10,10)); 41 jp1.setPreferredSize(new Dimension(200, 800)); 42 43 //实例化DrawListener对象 44 dl=new DrawListener(); 45 //循环为按钮面板添加按钮 46 for (int i = 0; i < buttonName.length; i++) { 47 JButton jbutton = new JButton(buttonName[i]); 48 jbutton.addActionListener(dl);//为按钮添加监听 49 jp1.add(jbutton); 50 } 51 52 JPanel jp2=new JPanel();//画布面板 53 jp2.setPreferredSize(new Dimension(970, 800)); 54 jp2.setBackground(Color.WHITE); 55 56 57 // 定义Color数组,用来存储按钮上要显示的颜色信息 58 Color[] colorArray = { Color.BLUE, Color.GREEN, 59 Color.RED, Color.BLACK,Color.ORANGE,Color.PINK,Color.CYAN, 60 Color.MAGENTA,Color.DARK_GRAY,Color.GRAY,Color.LIGHT_GRAY, 61 Color.YELLOW}; 62 //用于保存颜色按钮的面板 63 JPanel jp3=new JPanel(new GridLayout(1,colorArray.length,3,3)); 64 // 循环遍历colorArray数组,根据数组中的元素来实例化按钮对象 65 for (int i = 0; i < colorArray.length; i++) { 66 JButton button = new JButton(); 67 button.setBackground(colorArray[i]); 68 button.setPreferredSize(new Dimension(30, 30)); 69 button.addActionListener(dl);//为按钮添加监听 70 jp3.add(button); 71 } 72 //将面板添加到主窗体 73 this.add(jp1); 74 this.add(jp2); 75 this.add(jp3); 76 //添加按钮,作为当前颜色 77 JButton nowColor=new JButton(); 78 nowColor.setPreferredSize(new Dimension(40,40)); 79 nowColor.setBackground(Color.BLACK);//默认黑色 80 add(nowColor); 81 //设置窗体的组件可见,如果为FALSE就看不到任何组件 82 setVisible(true); 83 //获取画笔对象 84 g=jp2.getGraphics(); 85 dl.setG(g); 86 dl.setNowColor(nowColor); 87 //为面板添加鼠标监听,用于绘制图形 88 jp2.addMouseListener(dl); 89 jp2.addMouseMotionListener(dl); 90 } 91 92 } View Code drawDrawListener里面只写了画直线和曲线的方法,读者可以根据自己的需求添加,思路和方式都是一样的。Draw类里面有些需要注意的地方在这里提一下:一个是画笔g的获取一定要在窗体的可见之后采取获取,不然获取的画笔对象返回值会是null。二是要为图形按钮添加监听,DrawListener的实例化需要在setVisible方法之前,所以不建议使用构造方法直接传入g画笔参数,我使用的是set方法。最后是注意一下使用哪个添加方法,按钮使用的是addActionListener方法,画板面板使用的是addMouseListener和addMouseMotionListener方法。使用画板面板来获取画笔并给画面面板添加监听是为了让绘图的时候图形不会跑出面板外,这里的画笔和监听都由主窗体获得也是可以的,不过绘制时会出现线画出面板的问题。 画板的重绘: 到这里画板的制作已经基本实现了,我们已经可以在上面绘制各种各样的图形了。但是细心的人可能会发现一个问题,那就是如果把窗体最小化之后再次打开,画板上原本已经画好的东西会全部都消失了。这样子肯定是不行的,辛辛苦苦画的“大作”怎么能说说没就没了呢。那么为什么会出现这样的问题呢?要回答这个问题我们就需要先了解Java的绘图机制。做画图板我们使用的是Swing组件,这套组件是基于原先的AWT组件开发,在绘制的时候会调用系统的画图函数,这就是为什么我们可以从面板或者是窗体中获取画笔对象的原因。这也就是说Java中你所能够看到窗体,按钮或者其它的所有组件其实都是画出来。所以当我们点击窗体使它最小化或者改变大小的时候,原来的画的窗体就不能适应需要了,这时系统会调用JFrame的paint方法实现窗体的重绘,也就是再次画了一个新的窗体,而JFrame的paint方法只对窗体已经添加的组件有效,我们自己绘制的东西并没有写在paint方法里面,所以窗体重绘之后,我们原先绘制的图形也就消失了。要解决这个问题我们需要重写父类的paint方法。但是这样的话问题又来了,画图是在DrawListener类里面实现的,要怎么把它们弄到paint方法里面去呢? 当然方法可能有很多,这里我只介绍我所知道的:要把画出来的图形在paint方法中再次画出来,就需要有东西来保存画过的图形。保存可以使用数组或者集合,这里推荐使用集合,可以很方便的实现添加,而不需要去考虑大小的问题。数组的实现也大同小异,这里就不多做介绍。确定了使用集合,那么集合内保存什么类型的数据呢?毫无疑问应该保存的是图形的数据,但是集合使用泛型的话也只能保存同一种类型的数据,我们却有那么多种图形?这里就可以使用接口或者抽象类,我们只需要创建不同得图形类,让它继承抽象类或者是实现接口。然后每画一个图形就实例化一个图形的对象,存入集合中,最后在paint方法中遍历集合,重新绘制图形即可。 下面直接贴最终代码(仍然只写了直线和曲线),只是添加了几行代码,注意与前面比较。 //图形接口 package Cbs; //图形集合 public interface NetJavaShape { public abstract void draw(); } //直线类 package Cbs; import java.awt.Color; import java.awt.Graphics; import Cbs.NetJavaShape; public class ImpLine implements NetJavaShape{ Graphics g; int x1, y1,x2, y2; Color c; public ImpLine(Graphics g,int x1,int y1,int x2,int y2,Color c){ this.g=g; this.c=c; this.x1=x1; this.y1=y1; this.x2=x2; this.y2=y2; } public void draw() { g.setColor(c); g.drawLine(x1, y1, x2, y2); } } //DrawListener类 package Cbs; import java.awt.Color; import java.awt.Graphics; import java.util.List; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.ArrayList; import Cbs.NetJavaShape; import javax.swing.JButton; public class DrawListener implements ActionListener, MouseListener, MouseMotionListener { private Color color=Color.BLACK;//颜色属性,初始值为黑色 private Graphics g;//画笔属性 private String str;//保存按钮上的字符串,区分不同的按钮 private int x1,y1,x2,y2;//(x1,y1),(x2,y2)分别为鼠标的按下和释放时的坐标 private JButton nowColor;//当前颜色按钮 //保存图形对象的集合 private List<NetJavaShape> shapesArray = new ArrayList<NetJavaShape>(); //图形 private NetJavaShape shape; //在draw类中获取集合 public List<NetJavaShape> getShapesArray() { return shapesArray; } //获取Draw类的画笔对象 public void setG(Graphics g) { this.g = g; } //获取当前颜色按钮 public void setNowColor(JButton nowColor) { this.nowColor = nowColor; } @Override //鼠标拖动的方法 public void mouseDragged(MouseEvent e) { //画曲线的方法 if ("画曲线".equals(str)) { int x, y; x = e.getX(); y = e.getY(); //实例化对象,曲线也是直线画的所以不同新建一个曲线类了 shape=new ImpLine(g,x,y,x1,y1,color); //调用画图方法 shape.draw(); //将图形存入集合中 shapesArray.add(shape); // g.drawLine(x, y, x1, y1); x1 = x; y1 = y; } } @Override //鼠标移动方法 public void mouseMoved(MouseEvent e) { } @Override //鼠标单击方法 public void mouseClicked(MouseEvent e) { } @Override //鼠标按下方法 public void mousePressed(MouseEvent e) { g.setColor(color);//改变画笔的颜色 x1=e.getX();//获取按下时鼠标的x坐标 y1=e.getY();//获取按下时鼠标的y坐标 } @Override //鼠标释放方法 public void mouseReleased(MouseEvent e) { x2=e.getX();//获取释放时鼠标的x坐标 y2=e.getY();//获取释放时鼠标的y坐标 //画直线的方法 if ("画直线".equals(str)) { //实例化对象, shape=new ImpLine(g,x1,y1,x2,y2,color); //调用画图方法 shape.draw(); //将图形存入集合中 shapesArray.add(shape); // g.drawLine(x1, y1, x2, y2); } } @Override //鼠标进入方法 public void mouseEntered(MouseEvent e) { } @Override //鼠标退出方法 public void mouseExited(MouseEvent e) { } @Override //处理按钮上的鼠标点击动作 public void actionPerformed(ActionEvent e) { if ("".equals(e.getActionCommand())) { JButton jb = (JButton) e.getSource(); color = jb.getBackground(); nowColor.setBackground(color);//处理当前颜色 } else { str = e.getActionCommand(); } } } //draw类 package Cbs; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.GridLayout; import java.util.ArrayList; import java.util.List; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; /** * Draw类,用于界面的初始化 * @author CBS */ @SuppressWarnings("serial") public class Draw extends JFrame { private DrawListener dl; private Graphics g; //保存图形对象的集合 private List<NetJavaShape> shapesArray = new ArrayList<NetJavaShape>(); // 界面初始化方法 public void showUI() { setTitle("画图");//窗体名称 setSize(1200, 900);//窗体大小 setDefaultCloseOperation(3); setLocationRelativeTo(null);//窗体居中 FlowLayout layout = new FlowLayout(FlowLayout.LEFT);//流式布局左对齐 setLayout(layout);//窗体使用流式布局管理器 this.setResizable(false);//窗体大小不变 //使用数组保存按钮名 String buttonName[] = { "画直线", "画椭圆", "画曲线", "多边形", "橡皮擦", "拖动线","三角形", "画球形", "笔刷", "喷枪", "色子", "立体矩形", "立体圆", "立体三角","迭代分形", "现代分形", "枫叶", "画树", "mandelbrot集", "L-System", "迭代画线","迭代三角形", "谢尔宾斯基地毯", "画字符", "清空","吸管" ,"矩形","五角星","多线","字符"}; JPanel jp1=new JPanel(new GridLayout(15, 2,10,10));//用于保存图形按钮,使用网格布局 jp1.setPreferredSize(new Dimension(200, 800)); //实例化DrawListener对象 dl=new DrawListener(); //循环为按钮面板添加按钮 for (int i = 0; i < buttonName.length; i++) { JButton jbutton = new JButton(buttonName[i]); jbutton.addActionListener(dl);//为按钮添加监听 jp1.add(jbutton); } JPanel jp2=new JPanel();//画布面板 jp2.setPreferredSize(new Dimension(970, 800)); jp2.setBackground(Color.WHITE); // 定义Color数组,用来存储按钮上要显示的颜色信息 Color[] colorArray = { Color.BLUE, Color.GREEN, Color.RED, Color.BLACK,Color.ORANGE,Color.PINK,Color.CYAN,Color.MAGENTA,Color.DARK_GRAY,Color.GRAY,Color.LIGHT_GRAY,Color.YELLOW}; //用于保存颜色按钮的面板 JPanel jp3=new JPanel(new GridLayout(1,colorArray.length,3,3)); // 循环遍历colorArray数组,根据数组中的元素来实例化按钮对象 for (int i = 0; i < colorArray.length; i++) { JButton button = new JButton(); button.setBackground(colorArray[i]); button.setPreferredSize(new Dimension(30, 30)); button.addActionListener(dl);//为按钮添加监听 jp3.add(button); } //将面板添加到主窗体 this.add(jp1); this.add(jp2); this.add(jp3); //添加按钮,作为当前颜色 JButton nowColor=new JButton(); nowColor.setPreferredSize(new Dimension(40,40)); nowColor.setBackground(Color.BLACK);//默认黑色 add(nowColor); //设置窗体的组件可见,如果为FALSE就看不到任何组件 setVisible(true); //获取画笔对象 g=jp2.getGraphics(); dl.setG(g); dl.setNowColor(nowColor); //获取保存的集合 shapesArray=dl.getShapesArray(); //为面板添加鼠标监听,用于绘制图形 jp2.addMouseListener(dl); jp2.addMouseMotionListener(dl); } @Override //重写paint方法 public void paint(Graphics g) { //调用父类的paint方法,绘制界面上的组件 super.paint(g); //foreach遍历集合 for (NetJavaShape l : shapesArray) { l.draw(); } } } View Code 这里使用集合添加图形实现画板的重绘时,我是每实现一个图形就会新建一个类来保存图形的信息,这样图形类就会有很多。如果不想创建那么多的图形类可以把它们都放到一个类里面,设置一个type的参数,赋上按钮的名称。然后在draw方法中依据这个值判断是什么图形实现不同的画图方法。这样画板的所有功能基本就实现了,画板的项目也就到这里。 总结: 画图板的制作重要用到了Swing的组件,事件监听机制,Graphics绘图和画板的重绘以及集合的使用,抽象类或者是接口作为规范图形类的作用。