没有Java编写画图板程序细节-保存已画图形
一、为何我们要保存画图板上已画图形呢?
有很多人会问,为什么我们一定要保存画图板上已经画好了的图形呢?原因很简单。当我们在画图板上画完自己想画的图形后,如果进行以下几个操作,就会发现几个降低用户体验感的问题,而这些问题就是由于没有保存已画图形造成的。
首先第一种情况,如果你画完图形后,突然发现QQ或者微信来消息了,然后你一般会将画图板最小化然后去查收信息,当你再次回到画图板程序的时候你会惊奇的发现,你辛辛苦苦绘出的图片不翼而飞(哭了)。
最小化之前
最小化然后再次进入界面后
第二种情况,当你发现画图板的大小不合适,画到一半想要调整画图板大小时,一旦你调整画板的大小,你又会惊奇的发现,画好的图形又不见了!
调整画图板大小之前
调整大小之后
第三种情况,有时候你觉得画图板正好覆盖了一些你想看的内容,你接下来肯定会把画板界面往电脑屏幕边界拖从而来看你想看的被覆盖的内容,但是如果你拖过度了(把画板界拖到了屏幕外面了),那么恭喜你,图,又没了!!!
没有移动画图板界面之前
移动画图板界面到屏幕外
移动画图板界面然后拖回原处后
怎么样?是不是感觉体验感极差,如果这要是别人设计出来的画图板,你会有用下去的兴趣吗?还在等什么,咱们一起来找到问题的根源来解决这个坑爹的设计吧!
二、为何会出现已画图形消失的情况呢?
要想明白出现这个问题的根源呢,首先要明白一个原理:每当我们把将画图板最小化再打开时、拖动画图板到边缘再拉回来时或者是改变画图板大小时,都是画图板的Frame框架在不断调用它的paint方法的时候。其实这个很好理解,想想我们写的代码中有给Frame添加组件的部分,而这些组件包括框架本身是如何可视化让我们用户看见的呢?就是通过paint方法将这些组件“画”到了我们的电脑屏幕上才让我们看到了这些组件。那么当我们将画图板最小化,将画图板拖到边缘或者改变画图板大小的时候,都是画图板的可视化部分在改变的时候(最小化的时候画图板可视化部分全部消失,拖到边缘的时候画图板可视部分部分消失,改变大小的时候画图板可视部分大小改变)。既然画图板可视部分要改变了,就必须通过重新“画”一个新的面板上去才能实现状态的改变,这就是paint方法调用的原因。而Paint方法是一个java早已经定义好的一个方法,设计者并不知道我们用paint方法是来画什么图形的,设计者在设计之初只定义了用paint方法把这些组件画出来了,却并没有画我们自己创造的这些图形的这个部分。因此当程序自动调用paint方法时,就没有实现我们之前画的图形的可视化过程,只实现了框架组件的可视化过程,这就是为什么会出现已画图形消失的原因。
三、如何解决paint方法无法绘制用户已画图形呢?
1、保存当前已经绘制了的图形
①用什么来保存我们已经绘制了的图形?
试想我们绘制一个图形需要一些什么属性与方法呢?就拿直线来说,我们绘制一条直线首先需要知道这个直线的起始点与终止点,如果有设计需要的话还需要知道这条直线的颜色和粗细等等,当然还有一个最重要的属性,名字(例如“直线”),因为当我们绘制一个图形对象的时候我们要知道对象是哪个类型的图形,这样我们才能使用对应的方法来绘制这个类型的图形。既然一个图形通过它自己的属性和相应的方法能够绘制出相应的图形,那么我们不妨创建一个Shape类来实现保存的功能,将所有的图形有关信息保存到Shape对象中,再调用Shape对象中的绘制方法从而实现可视化图像的保存功能。
具体代码如下:
1 public class Shape { 2 private int x1,y1,x2,y2,x3,y3; 3 private String name; 4 private Color color; 5 6 7 public Shape(String name,Color color,int x1, int y1,int x2,int y2,int x3,int y3){ 8 this.x1 = x1; 9 this.y1 = y1; 10 this.x2 = x2; 11 this.y2 = y2; 12 this.x3 = x3; 13 this.y3 = y3; 14 this.name = name; 15 this.color = color; 16 } 17 18 19 public void drawshape(Graphics g){ 20 switch(name){ 21 case "直线": 22 g.setColor(color); 23 g.drawLine(x1, y1, x2, y2); 24 break; 25 case "三角形": 26 g.setColor(color); 27 g.drawLine(x1, y1, x2, y2); 28 g.drawLine(x1, y1, x3, y3); 29 g.drawLine(x2, y2, x3, y3); 30 break; 31 case "矩形": 32 g.setColor(color); 33 g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2), Math.abs(y1-y2)); 34 break; 35 } 36 37 38 39 } 40 41 }
②具体如何将这些图形保存到Shape对象中?
由于我们的图形不止一个,所以我们需要创建一个对象数组,例如Shape[]Shapearray = new Shape;来保存不同的图形。然后在同时继承了鼠标监视器、动作监视 器、鼠标动作监视器的监视器类中来不断往这个对象数组里面添加元素。例如当我们画 直线的时候,我们首先点击“直线”按钮与“颜色”两个按钮,这个时候我们监视器就 已经通过name属性和color属性保存了相应的名字和颜色,然后当我们通过鼠标点击 移动释放后得到x1,y1,x2,y2四个坐标,这个时候我们的监视器就已经通过判断名字颜色 以及坐标位置实现了绘图功能,那么我们需要添加的步骤呢就只是在绘制完图形以后继 续创建一个Shape类型的对象(通过构建函数初始化属性),然后再把这个对象赋给对 象数组里面的一个元素就实现了一个直线对象的保存。其它类型的对象以此类推。
具体代码如下:
1 public class Drawlistener implements ActionListener,MouseListener,MouseMotionListener{ 2 3 private int x1,y1,x2,y2,x3,y3,i=1,j=1,count=1,number = 0; 4 private String name; 5 private Color color = Color.BLACK,color2; 6 private Graphics gr; 7 private JFrame frame; 8 private Shape[] shapearray = new Shape[1000000]; 9 public Shape[] getshapearray(){ 10 return shapearray; 11 } 12 public void setgraphics(Graphics gr1){ 13 gr = gr1; 14 } 15 public void setcolor(Color color1){ 16 color2 = color1; 17 } 18 19 @Override 20 public void actionPerformed(ActionEvent e) { 21 // TODO Auto-generated method stub 22 if("".equals(e.getActionCommand())){ 23 JButton botton = (JButton)e.getSource(); 24 color = botton.getBackground(); 25 gr.setColor(color); 26 } 27 else{ 28 name = e.getActionCommand(); 29 } 30 System.out.println(name); 31 } 32 33 @Override 34 public void mouseClicked(MouseEvent e) { 35 // TODO Auto-generated method stub 36 if("三角形".equals(name)){ 37 x3 = e.getX(); 38 y3 = e.getY(); 39 gr.drawLine(x1, y1, x3, y3); 40 gr.drawLine(x2, y2, x3, y3); 41 i--; 42 Shape shape = new Shape(name,color,x1, y1, x2, y2, x3, y3); 43 shapearray[number++] = shape; 44 } 45 if("多边形".equals(name)){ 46 count =e.getClickCount(); 47 if(count==1){ 48 x3 = e.getX(); 49 y3 = e.getY(); 50 gr.drawLine(x3, y3, x2, y2); 51 Shape shape = new Shape("直线",color,x3,y3,x2,y2,x3,y3); 52 shapearray[number++] = shape; 53 x2 = x3; 54 y2 = y3; 55 } 56 else{ 57 gr.drawLine(x1, y1, x3, y3); 58 j--; 59 Shape shape = new Shape("直线",color,x1,y1,x3,y3,x3,y3); 60 shapearray[number++] = shape; 61 } 62 } 63 64 } 65 66 @Override 67 public void mousePressed(MouseEvent e) { 68 // TODO Auto-generated method stub 69 if("直线".equals(name)||"矩形".equals(name)){ 70 x1 = e.getX(); 71 y1 = e.getY(); 72 //System.out.println("x1 "+x1+"y1 "+y1); 73 } 74 if("三角形".equals(name)){ 75 if(i == 1){ 76 x1 = e.getX(); 77 y1 = e.getY(); 78 } 79 } 80 if("多边形".equals(name)&& j==1){ 81 x1 = e.getX(); 82 y1 = e.getY(); 83 } 84 if("可拖动直线".equals(name)||"连续曲线".equals(name)){ 85 x1 = e.getX(); 86 y1 = e.getY(); 87 } 88 } 89 90 @Override 91 public void mouseReleased(MouseEvent e) { 92 // TODO Auto-generated method stub 93 if("三角形".equals(name)){ 94 if(i == 1){ 95 x2 = e.getX(); 96 y2 = e.getY(); 97 gr.drawLine(x1, y1, x2, y2); 98 i++; 99 } 100 } 101 if("直线".equals(name)||"可拖动直线".equals(name)){ 102 x2 = e.getX(); 103 y2 = e.getY(); 104 gr.drawLine(x1, y1, x2, y2); 105 //System.out.println("x1 "+ x1+"y1 "+y1+"x2 "+x2+"y2 "+y2); 106 Shape shape = new Shape("直线",color,x1,y1,x2, y2, x3, y3); 107 shapearray[number++] = shape; 108 109 110 } 111 if("矩形".equals(name)){ 112 x2 = e.getX(); 113 y2 = e.getY(); 114 gr.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2), Math.abs(y1-y2)); 115 Shape shape = new Shape(name,color,x1,y1, x2, y2, x3, y3); 116 shapearray[number++] = shape; 117 118 } 119 if("多边形".equals(name)&&j==1){ 120 x2 = e.getX(); 121 y2 = e.getY(); 122 gr.drawLine(x1, y1, x2, y2); 123 Shape shape = new Shape("直线",color,x1,y1,x2,y2,x3,y3); 124 shapearray[number++] = shape; 125 j++; 126 127 } 128 } 129 130 @Override 131 public void mouseEntered(MouseEvent e) { 132 // TODO Auto-generated method stub 133 134 } 135 136 @Override 137 public void mouseExited(MouseEvent e) { 138 // TODO Auto-generated method stub 139 140 } 141 142 @Override 143 public void mouseDragged(MouseEvent e) { 144 // TODO Auto-generated method stub 145 System.out.println("我在努力拖动!"); 146 if("可拖动直线".equals(name)){ 147 gr.setColor(color2); 148 gr.drawLine(x1, y1, x3, y3); 149 x3 = e.getX(); 150 y3 = e.getY(); 151 gr.setColor(color); 152 gr.drawLine(x1, y1, x3, y3); 153 } 154 if("连续曲线".equals(name)){ 155 x3 = e.getX(); 156 y3 = e.getY(); 157 gr.drawLine(x1, y1, x3, y3); 158 Shape shape = new Shape("直线",color,x1,y1,x3,y3,x3,y3); 159 shapearray[number++] = shape; 160 x1 = x3; 161 y1 = y3; 162 } 163 } 164 165 @Override 166 public void mouseMoved(MouseEvent e) { 167 // TODO Auto-generated method stub 168 169 } 170 171 }
③保存了对象之后如何输出这些对象呢
之前已经提到了我们原本写的图形之所以消失就是因为Java设计者在设计JFrame类的时候并没有在paint方法写我们之前画的那些图形的绘制,那么我们要做的就很简单了,就是重写JFrame的paint方法。而方法的重写是建立在继承关系上的,所以这个时候我们需要新创建一个类去继承JFrame类,这个类里面的内容和之前实现画图板的类基本一样,要做的只是把创建的JFrame对象删去,然后对所有对JFrame对象的属性或者方法的访问由“对象.”改为“this.”,因为你已经继承了JFrame类了,就不需要在类中在创建一个类的对象了。
紧接着要做的就是重写paint方法。具体操作呢:首先查看JFrame类的源代码,找到paint方法复制过来,然后在方法体里面写上 super.paint(g),因为我们重写方法还是要实现父类方法已有的功能,然后再在这个基础上写我们新创建的功能。
最后,将监视器保存的对象数组通过get方法传送到这个类里面来,通过for循环来将每一个对象绘制到面板上,这样就实现了对象的输出了。
具体代码如下:
1 public class Drawpanel extends JFrame{ 2 Drawlistener drawlistener = new Drawlistener(); 3 private Shape[] shapearray; 4 public void showpanel(){ 5 this.setSize(1000,1000); 6 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 7 this.setLocationRelativeTo(null); 8 this.setLayout(new FlowLayout()); 9 String[] shape = {"直线","矩形","三角形","多边形","连续曲线","可拖动直线"}; 10 for(int i = 0; i < shape.length;i++){ 11 JButton shapebotton = new JButton(shape[i]); 12 Dimension shapedimension = new Dimension(100,50); 13 shapebotton.setPreferredSize(shapedimension); 14 shapebotton.addActionListener(drawlistener); 15 this.add(shapebotton); 16 } 17 Color[] color = {Color.RED,Color.BLUE,Color.GREEN}; 18 String[]colorname = {"红色","蓝色","绿色"}; 19 for(int j = 0; j < color.length;j++){ 20 JButton colorbotton = new JButton(); 21 Dimension colordimension = new Dimension(100,50); 22 colorbotton.setPreferredSize(colordimension); 23 colorbotton.setBackground(color[j]); 24 colorbotton.addActionListener(drawlistener); 25 colorbotton.setToolTipText(colorname[j]); 26 this.add(colorbotton); 27 } 28 this.addMouseListener(drawlistener); 29 this.addMouseMotionListener(drawlistener); 30 this.setVisible(true); 31 Graphics gr = this.getGraphics(); 32 drawlistener.setgraphics(gr); 33 drawlistener.setcolor(this.getBackground()); 34 35 } 36 public void paint(Graphics g){ 37 super.paint(g); 38 shapearray = drawlistener.getshapearray(); 39 for(int i = 0; i < shapearray.length;i++) 40 { 41 if(shapearray[i] != null){ 42 shapearray[i].drawshape(g); 43 } 44 else{ 45 break; 46 } 47 48 } 49 } 50 51 52 53 public static void main(String[] args){ 54 Drawpanel drawpanel = new Drawpanel(); 55 drawpanel.showpanel(); 56 } 57 58 59 60 }
这样就解决了以上所说的问题了,上面的三段代码已经能够编写一个较为简单的画图板,希望能帮助到你们!