當柳上原的風(fēng)吹向天際的時候...

          真正的快樂來源于創(chuàng)造

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


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


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

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

          1.工具欄菜單的配置文件
             <items>    
                  
                      
                  
          <item>
                      
          <icon>tollbar_sqlwindow/run.gif</icon>
                      
          <function>run</function>
                      
          <description>執(zhí)行所選擇的Sql語句</description>
                  
          </item>
                  
                  
          <item>
                      
          <icon>tollbar_sqlwindow/batchRun.gif</icon>
                      
          <function>batchRun</function>
                      
          <description>批量執(zhí)行所選擇的Sql語句,以分號為分割單位</description>
                  
          </item>
                  
                  
          <item>
                      
          <icon>tollbar_sqlwindow/format.gif</icon>
                      
          <function>format</function>
                      
          <description>格式化所選擇的Sql語句</description>
                  
          </item>
                  
                  
              
          </items>
           
          以上子項里,icon是工具欄按鈕的對應(yīng)圖片,function是點擊按鈕后響應(yīng)的具體函數(shù)名,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.根據(jù)讀出的信息生成按鈕項并添加到工具欄。
             
              for (ToolbarItem item : ToolbarItemLoader.getItems()) {
                  toolbar.add(
          new ToolbarButton(item.getIcon(), item.getFunction(),
                          item.getDescription()));
              }

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


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

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

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

                          
          // 執(zhí)行函數(shù)
                          executeFunction(function, selectedText);
                      }
                  });
              }
          }

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

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

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

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

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

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

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

                  SqlTextDialog dlg 
          = new SqlTextDialog("調(diào)用函數(shù)" + fucntionName
                          
          + "出現(xiàn)異常", sb.toString(), 400300);
                  dlg.setVisible(
          true);
              }
          }

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

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

          }

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

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

          就是這些,再見吧!

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

          Feedback

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

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

          建議很好啊,不過現(xiàn)在我還不熟悉它們,只能用熟的來開發(fā)了。  回復(fù)  更多評論
            

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

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

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

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

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

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

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

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


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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 河北省| 郁南县| 资阳市| 泰宁县| 建瓯市| 拉孜县| 沅江市| 伽师县| 营口市| 保定市| 津市市| 承德县| 杨浦区| 泽普县| 乌拉特前旗| 镇坪县| 潮安县| 丰县| 盖州市| 祥云县| 揭东县| 武鸣县| 天全县| 金湖县| 汉沽区| 儋州市| 太湖县| 辽阳县| 金坛市| 班戈县| 巫溪县| 信阳市| 博兴县| 平顺县| 玉山县| 高平市| 鄄城县| 平昌县| 商都县| 叙永县| 六盘水市|