Java編寫畫圖板程式細節-保存已畫圖形

来源:https://www.cnblogs.com/782687539-nanfu/archive/2019/01/23/10311362.html
-Advertisement-
Play Games

沒有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方法寫我們之前畫的那些圖形的繪製,那麼我們要做的就很簡單了,就是重寫JFramepaint方法。而方法的重寫是建立在繼承關係上的,所以這個時候我們需要新創建一個類去繼承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 }

 

 

這樣就解決了以上所說的問題了,上面的三段代碼已經能夠編寫一個較為簡單的畫圖板,希望能幫助到你們!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、實現基本CRUD功能 使用MyBatis對數據完整的操作,也就是CRUD功能的實現。根據之前的內容,要想實現CRUD,只需要進行映射文件的配置。 範例:修改EmpMapper.xml文件,實現CRUD 此時已經完成了映射文件的配置。就可以利用SqlSession類對象完成具體的操作,方法如下: ...
  • 前面介紹了類的多態性,來自於雞類的實例chicken,既能用來表達公雞實例,也能用來表達母雞實例。可是這導致了一個問題,假如在call方法內部需要手工判斷輸入參數屬於公雞實例還是母雞實例,那該如何是好?所謂“雄兔腳撲朔,雌兔眼迷離,雙兔傍地走,安能辨我是雄雌”,固然編譯器在運行之時能夠自動判斷這是哪 ...
  • 輸入兩個整數 n,m ,求在 m 個數中取 n 個數的方案總數: 1 var 2 n,m:longint; 3 function c(n,m:longint):qword; 4 var 5 i:longint; 6 begin 7 c:=1; 8 for i:=1 to n do 9 c:=c*(m ...
  • Python函數總結 一、函數的基本用法 函數是對程式邏輯進行結構化或是過程化的一種編程方法,其是組織好的,可重覆使用的,用來實現單一,或者相同功能的代碼段。 函數提高了應用點的模塊性和代碼的重覆利用率 本質:函數是對功能的封裝 形式參數:簡稱形參,本質是一個沒有值的變數 ​ 實際參數:簡稱實參,本 ...
  • 什麼是工廠設計模式? 看了好多文章,寫的五花八門,以下是我對工廠模式的理解,重點是文末我通過大量的文章總結出的抽象工廠模式和工廠模式以及之間的區別,可以讓你更好的認識工廠模式。 工廠設計模式,顧名思義,就是用來生產對象的,在java中,萬物皆對象,這些對象都需要創建,如果創建的時候直接new該對象, ...
  • 一.運算符邏輯運算and:兩邊都真則真or:有真則真not:非假是真順序:()>==>not==>and>=or二.while.. elsewhile 條件: 代碼塊else: 當條件為假的時候執行三.主要內容1.編碼 1.最早的電腦編碼是ASCII,美國人創建的,包含了英文字母(大小寫字母). ...
  •   本例所繪圖形選自《Go語言程式設計》(作者:Alan A. A. Donovan與Brian W. Kernighan)。 完整代碼 效果 說明   1、這裡對節點與箭頭線段style的定義放在了tikzpicture環境定義的參數設置中。實際工作中,對於 ...
  • 一、PHP消息隊列實現及應用 二、消息隊列的優缺點 三、消息隊列的配置和準備工作 案例如下: 下麵是隊列表欄位及屬性 四、Mysql訂單隊列 1、接受訂單,並寫入數據 order.php 2、隊列系統處理隊列中的訂單併進行標識goods.php 3、定時任務。每分鐘執行一次goods.sh 要會sh ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...