Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 427|回复: 0

[Swing学习]使用反射简化Swing工具栏按钮子项的设计

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-8 23:56:57 | 显示全部楼层 |阅读模式
    传统的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(
         this
         ,
         new
          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(),
         400
         ,
         300
         );
             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()取得其真正异常。
       

       
    通过以上五步,按钮的生成和响应就可以被一个配置文件所控制,这种方式改善了程序的可维护性,反射是实现改进的五个步骤的核心环节。另外反射也是诸多框架和通用性组件的常用技术之一,值得每个程序员好好掌握。
       

       

       
    复制代码
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 10:38 , Processed in 0.324851 second(s), 38 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表