沒有Java編寫畫圖板程式細節-保存已畫圖形 一、為何我們要保存畫圖板上已畫圖形呢? 有很多人會問,為什麼我們一定要保存畫圖板上已經畫好了的圖形呢?原因很簡單。當我們在畫圖板上畫完自己想畫的圖形後,如果進行以下幾個操作,就會發現幾個降低用戶體驗感的問題,而這些問題就是由於沒有保存已畫圖形造成的。 首 ...
沒有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 }
這樣就解決了以上所說的問題了,上面的三段代碼已經能夠編寫一個較為簡單的畫圖板,希望能幫助到你們!