Swing组件国际化

很长一段时间一直在做 Applet 开发,前不久客户提出要做界面的国际化。我也有一直思考这个问题, Java 本身对国际化支持很好的,最简单的方式就是在创建每个 Component 之前,把文本就国际化然后再塞给这个组件。例如: (resources 是根据 Locale 读入的 ResourceBundle)
java 代码
  1. JFrame frame = new JFrame();   
  2. frame.setTitle(resources.getString("Title"));   
这样做实在太不雅,另外也无法在运行时随着 Locale 改变而改变界面的语言。
在网上看到一篇文章 http://www.progdoc.de/papers/intSwing/intswing/intswing.html ,提到一种很有趣的做法,通过设置每个组件的 ComponentUI ,在 ComponentUI 渲染该组件之前,把文本国际化。
先介绍一下 ComponentUI Swing 组件是基于 MVC 模式的,但同经典的 MVC 有点不一样, Swing View Controller 合并到同一个委托对象中: ComponentUI ,该对象都有 paint() 方法负责渲染其关联的组件。
那么怎么知道每个组件用的什么 ComponentUI 来画这个组件呢?有一个叫 UIManager 的大总管来负责设置整个界面的样式,通过 setLookAndFeel(LookAndFeel) 方法设置 LookAndFeel ,而 LookAndFeel 的实现中即包括对所有组件的 ComponentUI 的设置。
例如: Windows 风格的界面
java 代码
  1. public class WindowsLookAndFeel extends BasicLookAndFeel{   
  2.              protected void initClassDefaults(UIDefaults table){   
  3.                     super.initClassDefaults(table);   
  4.     
  5.                     final String windowsPackageName = "com.sun.java.swing.plaf.windows.";   
  6.     
  7.                     Object[] uiDefaults = {   
  8.                        "ButtonUI", windowsPackageName + "WindowsButtonUI",   
  9.                          "CheckBoxUI", windowsPackageName + "WindowsCheckBoxUI",   
  10.                                  "CheckBoxMenuItemUI", windowsPackageName + "WindowsCheckBoxMenuItemUI",   
  11.                               "LabelUI", windowsPackageName + "WindowsLabelUI",   
  12.                             "RadioButtonUI", windowsPackageName + "WindowsRadioButtonUI",   
  13.                                     "RadioButtonMenuItemUI", windowsPackageName + "WindowsRadioButtonMenuItemUI",   
  14.                    ……  
设置渲染 Button 使用 WindowsButtonUI ,画 Label 使用 WindowsLabelUI….. 等等
所以我们要定制自己的国际化控件继承 WindowsLookAndFeel ,然后重载 initClassDefaults 方法,在其中插入自己指定的 ComponentUI
java 代码
  1. public class MLWindowsLookAndFeel extends WindowsLookAndFeel {   
  2.     protected void initClassDefaults(UIDefaults table) {   
  3.         super.initClassDefaults(table);   
  4.         Object[] classes = {   
  5.                            "LabelUI", mlPackage + "MLWindowsLabelUI",   
  6.                                                         ………………   
  7.         };   
  8.         table.putDefaults(classes);   
  9.     }   
  10. }  
这样任何一个 JLabel 显示的时候都调用我们自定义的 MLWindowsLabelUI 中的 paint() 方法
我们就可以在这个地方做手脚了
java 代码
  1. public class MLWindowsLabelUI extends WindowsLabelUI {   
  2.     private final static MLWindowsLabelUI ML_WINDOWSLLABEL_UI = new  
  3.             MLWindowsLabelUI();   
  4.     /**  
  5.      * 必须重载该方法,因为UIManager会调用该方法获得其实例,所以不重写会获得其父类的实例  
  6.      * @param c JComponent  
  7.      * @return ComponentUI  
  8.      */  
  9.     public static ComponentUI createUI(JComponent c) {   
  10.         //因为树上的Cell和下拉框中显示也用了Label控件,但其无需国际化,返回其父类的实例   
  11.         if(c instanceof TreeCellRenderer ||c instanceof ListCellRenderer){   
  12.             return new WindowsLabelUI();   
  13.         }   
  14.         return ML_WINDOWSLLABEL_UI;   
  15.     }   
  16.     /**  
  17.      * 在格式化Label的文本前,将其国际化,再调用父类的格式文本方法,  
  18.      * 若在这之后重载其他方法以实现国际化会不正确,因为已格式化的文本可能跟原来不一样  
  19.      * 比如过长的文体会用...代替  
  20.      */  
  21.     protected String layoutCL(JLabel label,FontMetrics fontMetrics,String text,Icon icon,Rectangle viewR,Rectangle iconR,Rectangle textR) {   
  22. return super.layoutCL(label,fontMetrics,MessageUtil.getMessage(text),icon,viewR,iconR, textR);   
  23.     }   
  24. }  
有两个地方需要注意的:首先必须重载父类的 createUI 方法,否则当调用该类的 createUI 是返回的还是父类的实现,所以不会有任何效果,因为这个我 Debug 了好长时间。
再就是,我们也并不会真的去重载 paint() 方法,因为要画一个控件是个很麻烦的事情,我们只需要找出其画需要的文本的那个方法然后重载,调用其父类对应方法传入已国际化的文本就 OK 了。当然要找出合适的方法重载也有点麻烦,需要大概把 paint() 执行流程通读一边。对于 Label, 我之前是重载 paintEnabledText() ,但发现当 Label 长度不够时,文本就会变成省略号,结果以这个为 Key 去查资源文件肯定不对,所以要找到合适的方法可能需要反复试验。
使用直接继承的方式,现在只能局限于 Windows 风格的界面,可考虑使用装饰模式,我们的 LookAndFeel 直接继承 BasicLookAndFeel ,然后构造方法中传入另一个 LookAndFeel 的实例,将其他方法的实现都委托给该 LookAndFeel LabelUI 也使用同样的方式。这样应该就可适用于其他风格的界面了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值