當柳上原的風吹向天際的時候...

          真正的快樂來源于創造

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
          傳統的Swing工具欄的按鈕從生成到響應總是需要一堆相似的代碼來完成的,如下:
          生成工具欄按鈕的代碼示例:
          .....
          reopenBtn=new JButton(ResourceUtil.ToolbarMain_Reopen_ImageIcon);
          reopenBtn.setToolTipText(
          "刷新數據庫內容");
          toolbar.add(reopenBtn);
          // toolbar是工具欄,JToolBar的示例


          響應上面這個按鈕的點擊事件的代碼如下:
          view.getToolbarPanel().getReopenBtn().addActionListener(new ActionListener() {
              
          public void actionPerformed(ActionEvent e) {
                  .. 
          // 具體處理略
              }
          });


          如果只是這點代碼,程序整體確實沒有什么問題,但數量多了就不得了,試想想看,按照MVC的放置原則,生成的代碼和響應點擊的代碼應該放在兩個類中,如果需要修改就是兩個修改點;而工具欄按鈕一般是較多的,假設有十個按鈕那么就意味著十對修改點,如果數量再多呢?這對軟件的可維護性可謂一個災難,也為系統的隱患埋下了伏筆。有人說這就要考驗維護者對系統的理解和對代碼的責任心了,對這種轉移問題和把維護人員等同于機器的觀點作者不敢茍同,框架的設計者不能把自己應該盡到的責任推卸給維護者。

          如果有效利用XML和反射等手段,我們可以做到工具欄菜單項的可配置化。具體來說就是,將菜單項的文字,圖片和點擊后的響應函數都在XML配置文件中配置好,程序啟動時去讀取文件生成菜單,點擊菜單項后會動態的通過反射找到具體需要處理的函數。這樣做以后,修改一個按鈕對應的功能定位代碼,或是增刪一個按鈕及其功能就很容易了。下面來看具體的做法:

          1.工具欄菜單的配置文件
             <items>    
                  
                      
                  
          <item>
                      
          <icon>tollbar_sqlwindow/run.gif</icon>
                      
          <function>run</function>
                      
          <description>執行所選擇的Sql語句</description>
                  
          </item>
                  
                  
          <item>
                      
          <icon>tollbar_sqlwindow/batchRun.gif</icon>
                      
          <function>batchRun</function>
                      
          <description>批量執行所選擇的Sql語句,以分號為分割單位</description>
                  
          </item>
                  
                  
          <item>
                      
          <icon>tollbar_sqlwindow/format.gif</icon>
                      
          <function>format</function>
                      
          <description>格式化所選擇的Sql語句</description>
                  
          </item>
                  
                  
              
          </items>
           
          以上子項里,icon是工具欄按鈕的對應圖片,function是點擊按鈕后響應的具體函數名,description是用于ToolTipText的文字,這些信息都會被程序讀取出來。

          2.讀取配置文件中的信息
              List<ToolbarItem> items=new ArrayList<ToolbarItem>();
              
              
          // 下面開始讀取sqlWndToolbar.xml得到菜單項
              try {
                  SAXReader reader 
          = new SAXReader();
                  InputStream is
          =TreeMenuPanel.class.getResourceAsStream(“sqlWndToolbar.xml”);// toolbar.xml是具體文件名
                  
                  Document document 
          = reader.read(is);
                  Element rootElm 
          = document.getRootElement();
                  
                  List
          <Element> elms = rootElm.elements("item");
                  
          for (Element elm : elms) {
                      String icon
          =elm.elementText("icon");
                      String function
          =elm.elementText("function");
                      String description
          =elm.elementText("description");
                      
                      ToolbarItem btn
          =new ToolbarItem(icon,function,description);
                      items.add(btn);
                  }    
              } 
          catch (Exception ex) {
                  DlgUtil.popupErrorDialog(
          "無法讀取文件"+ResourceUtil.SqlWndToolbar_XMLFile);
                  ex.printStackTrace();
              }
              上述代碼中,ToolbarItem是包括icon,function,description 三個字符串子項的JavaBean。
              
          3.根據讀出的信息生成按鈕項并添加到工具欄。
             
              for (ToolbarItem item : ToolbarItemLoader.getItems()) {
                  toolbar.add(
          new ToolbarButton(item.getIcon(), item.getFunction(),
                          item.getDescription()));
              }

          下面就是添加完成的工具欄:


              ToolbarItemLoader.getItems()會得到上面第二段代碼中的items的引用,然后遍歷得到子項后就可以生成按鈕了。但注意一下,生成的按鈕是自定義的ToolbarButton類實例而不是JButton的子類實例,ToolbarButton繼承自JButton但多了一個function屬性,這個屬性對于事件響應是必不可少的,請看下面的代碼:
              
          4.添加工具欄菜單按鈕的事件響應:
          for (Component c : toolbar.getComponents()) {
              
          if (c instanceof ToolbarButton) {
                  
          final ToolbarButton btn = (ToolbarButton) c;

                  btn.addActionListener(
          new ActionListener() {
                      
          public void actionPerformed(ActionEvent e) {
                          
          // 要執行的函數
                          String function = btn.getFunction();

                          
          // 所選擇的文本
                          String selectedText = inputTxt.getSelectedText();

                          
          // 執行函數
                          executeFunction(function, selectedText);
                      }
                  });
              }
          }

          上面代碼就顯示了ToolbarButton的function屬性,它作為一個函數的參數傳了出去,這個函數用反射來具體定位函數,具體來說就是,function就是要真正調用的函數名。

          5.用反射調用具體的函數executeFunction.
          private void executeFunction(String fucntionName, String selectedText) {
              
          // 利用反射去找對應函數
              try {
                  
          // 得到實例對應的類
                  Class<?> cls = this.getClass();

                  
          // 通過反射得到方法
                  Method method = cls.getMethod(fucntionName,
                          
          new Class[] { String.class });

                  
          // 通過反射調用對象的方法
                  method.invoke(thisnew Object[] { selectedText });
              } 
          catch (NoSuchMethodException e) {
                  
          // 找不到方法時

                  DlgUtil.popupErrorDialog(
          "找不到方法" + fucntionName + ".");
              } 
          catch (IllegalAccessException e) {
                  
          // 當訪問權限不夠時

                  DlgUtil.popupErrorDialog(
          "方法" + fucntionName + "的訪問權限不夠.");
              } 
          catch (InvocationTargetException e) {
                  
          // 當調用的函數拋出異常時
                  Exception tragetException = (Exception) e.getTargetException();

                  StringBuilder sb 
          = new StringBuilder();
                  sb.append(
          "調用函數" + fucntionName + "出現異常,");
                  sb.append(
          "具體的異常信息為" + tragetException.getMessage() + ".");

                  SqlTextDialog dlg 
          = new SqlTextDialog("調用函數" + fucntionName
                          
          + "出現異常", sb.toString(), 400300);
                  dlg.setVisible(
          true);
              }
          }

          通過以上的反射處理后,如果點擊的是
          <item>
              
          <icon>tollbar_sqlwindow/format.gif</icon>
              
          <function>format</function>
              
          <description>格式化所選擇的Sql語句</description>
          </item>

          這段信息對應的按鈕,那么本類的format函數就會得到調用。
          public void format(String selectedText) throws Exception {

          }

          上面需要注意的有幾點:
          一是被反射調用的函數的訪問權限需要公有,否則會發生IllegalAccessException異常;二是函數名一定要和配置文件中的function節點對應好,否則會拋出NoSuchMethodException異常,三是函數有自己的異常拋出后,需要用e.getTargetException()取得其真正異常。

          通過以上五步,按鈕的生成和響應就可以被一個配置文件所控制,這種方式改善了程序的可維護性,反射是實現改進的五個步驟的核心環節。另外反射也是諸多框架和通用性組件的常用技術之一,值得每個程序員好好掌握。

          就是這些,再見吧!

          posted on 2010-05-18 22:04 何楊 閱讀(2383) 評論(7)  編輯  收藏

          Feedback

          # re: 使用反射簡化Swing工具欄菜單按鈕子項的設計 2010-05-19 13:43 BeanSoft
          我個人認為如果采用 Netbeans RCP 或者新的 Swing Application Framework 會更好些. 只可惜了 JDK 1.4 下沒多少開發框架.  回復  更多評論
            

          # re: 使用反射簡化Swing工具欄菜單按鈕子項的設計 2010-05-19 14:20 何楊
          @BeanSoft

          建議很好啊,不過現在我還不熟悉它們,只能用熟的來開發了。  回復  更多評論
            

          # re: 使用反射簡化Swing工具欄菜單按鈕子項的設計 2010-05-19 17:25 kunrey
          可以看一下spring-richclient 采用的是這種思想,不過不會指定調用方法,這個稍微封裝一下應該不難  回復  更多評論
            

          # re: 使用反射簡化Swing工具欄菜單按鈕子項的設計 2010-05-19 17:38 何楊
          @kunrey

          spring-richclient沒有接觸過。Spring什么時候弄出個桌面框架的?  回復  更多評論
            

          # re: 使用反射簡化Swing工具欄菜單按鈕子項的設計 2010-05-20 09:58 點對點
          @何楊
          spring-rich-client框架的思想非常不錯,看得使人賞心悅目的  回復  更多評論
            

          # re: 使用反射簡化Swing工具欄菜單按鈕子項的設計 2010-05-20 10:02 何楊
          @點對點

          謝謝,既然大家都說好,那看來要研究一番了。
            回復  更多評論
            

          # re: 使用反射簡化Swing工具欄菜單按鈕子項的設計 2010-05-21 11:04 何楊
          @點對點

          spring-rich-client才1.1.0版,再學一個桌面框架耗費挺大的,另外也不清楚它和Spring主體到底是什么關系,如果開發團隊力量小導致項目無疾而終就虧大了。我打算不預先抄底,等它成氣候再說。  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 丹凤县| 施秉县| 宣武区| 宜章县| 威海市| 哈巴河县| 遂溪县| 视频| 运城市| 太湖县| 那坡县| 喀喇| 嘉义市| 三明市| 饶河县| 宁海县| 东海县| 读书| 定结县| 修文县| 封丘县| 南汇区| 长春市| 霍林郭勒市| 商丘市| 阜新市| 青河县| 永定县| 普洱| 辰溪县| 平乡县| 怀化市| 岳普湖县| 蒙城县| 万源市| 宜兰县| 和平区| 穆棱市| 阿巴嘎旗| 德州市| 莱阳市|