Swing Application Framework 簡單介紹(二)

01:18下午 一月 20, 2009 in category Swing by UndeadJ


看完
Swing Application Framework 簡單介紹(一),有些人可能心已經死了一半,還不是差不多,還不是做同樣的事,並沒有增加太多的便利性,整個工作量還是差不多。

這時候第二點的重要性就出來了 資源取得與國際化
       
在以前寫
Swing時,很多時候可能會為(每個)元件設定一些它自己本身的屬性,像是文字、圖片、顏色、字型等等。
   
當元件一多的時候,程式裡面就會滲雜一堆設定元件屬性的程式碼。
   
不但程式看起來很又臭又長,而且當程式要轉換到其他地方或平台的話,語系轉換的工作,是很不方便的。
      
JSR-296參考了Spring Framework提供了一種新的資源注入規範(Resource injection principles),可以讓我們更方便的修改或翻譯成其他語言。
      
它利用一個 [YourClassName].
properties 檔案來做作為元件屬性的描述,這個檔案必須放在你程式所在位置的【resource】目錄下    

描述方式是採用key-value的方式,來對元件的屬性做設定
      
例如:

  • Label的文字            label.text = Hello World!
  • Label的背景顏色      label.background = 255,255,0
  • Label的前景顏色      label.foreground = 0, 0, 0
  • Label的字型            label.font = Lucida-PLAIN-48
  • Label的圖片            label.icon = abc.png 

描述好後,只要在程式中,利用元件的setName(String name)方法,就可以設定某元件的屬性。

以上面的例子就是      

JLabel label = new JLabel();
label.setName("label");
       
這樣一來,語系的轉換就變得很容易。只要事先在.properties 中,定義好每個語系元件的顯示方式就可以了。
       
類似這樣:
       
    button_TW.text = 哈囉 !
    button_CN.text = 哈啰 !
    button_EN.text = Hello !
       
然後利用Locale就可以輕鬆辦到
       

import java.util.Locale;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jdesktop.application.SingleFrameApplication;
       
public class SampleResourceDemo extends SingleFrameApplication {
    private JFrame f;
    private JPanel panel;
    private JButton I18N;
       
   @Override
    protected void startup() {               
        f = getMainFrame();
        panel = new JPanel();
        panel.setSize(300, 300);
        panel.add(createMainPanel());
        f.add(panel);
        show(f);
    }
       
    private JComponent createMainPanel() {               
        I18N = new JButton();
        I18N.setName("button_"+Locale.getDefault().getCountry());
        return I18N;
    }
       
    public static void main(String[] args) {               
        launch(SampleResourceDemo.class, args);
    }

另外也可以在.properties檔裡面,定義好一些共用的資源,然後利用ApplicationContextResourceManager來取得。
     
先前提到在
Swing Application Framework中,都是利用ApplicationContext來提供程式執行時的一些服務,取得資源就是其中一項。
     
ApplicationContext採用的是Design Pattern中的Singleton Pattern,所以不能直接建立實體,可以利用Application中提供的getContext()來取得ApplicationContext的實體。
 

ApplicationContext appContext = getContext();   

 

然後在取得實體後, 就可以取得相對應的ResourceMap

   
ApplicationContext appContext = getContext();
ResourceMap resourceMap = appContext.getResourceMap();

ResourceMap類別利用resource bundles的方式,負責將.properties的字串,轉換、注入到元件中,透過setName(String name)injectComponent(java.awt.Component target),讓元件自動綁定(bind)這些資源
      
或許有人會有這個問題:為什麼先前的例子,元件不需要經過
injectComponent(java.awt.Component target)這個動作,而只需要setName(String name),就可以和資源綁定(bind)?
      
這是因為在SingleFrameApplication類別中的各種
show()方法都幫我們做好了。若是要自己為元件做資源綁定工作的話,就一定要做這二個動作。
      
再來一個問題就是為什麼需要自己來做這件事,通通交給
SingleFrameApplication類別不就好了?
      
有時候我們可能不會去直接繼承
SingleFrameApplication類別,而是繼承其它元件。
      
這樣的話,當程式一大時,每個類別可以負責自己要做的事,整個程式架構會更加清楚。這時候就必需自己做這件事(資源綁定)
      
下面是個簡單的例子:
      

import org.jdesktop.application.SingleFrameApplication;

public class injectComponentDemo2 extends SingleFrameApplication{

    @Override
    protected void startup() {
        show(new injectComponentDemo());
    }
  
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        launch(injectComponentDemo2.class, args);
    }
}
      
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;

public class injectComponentDemo extends JPanel{
    public injectComponentDemo(){   
        ApplicationContext ctx = SingleFrameApplication.getInstance().getContext();
        ResourceMap resource = ctx.getResourceMap(injectComponentDemo.class);
        setName("panel");
        JLabel label = new JLabel();
        label.setName("label");       
        resource.injectComponent(label);
       
       JButton button = new JButton();       
        button.setName("button");  
        resource.injectComponent(button);
       
        add(label);
        add(button);
        resource.injectComponent(this);     
   }
}

上面元件注入資源的方式是採用一個一個注入的,ResourceMap類別也提供了一次注入全部元件(嚴謹一點的說法是:某容器(元件)內裝的所有元件),只要在全部配置(加入)完畢後,呼叫injectComponents(java.awt.Component root)

然後把最上層的元件(也就是裝有其它元件的容器)傳入,injectComponents(java.awt.Component root)會自動幫此容器內的所有元件做資源綁定的工作。
      
上面的改法就是

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;

public class injectComponentDemo extends JPanel{
   
    public injectComponentDemo(){       
        ApplicationContext ctx = SingleFrameApplication.getInstance().getContext();
        ResourceMap resource = ctx.getResourceMap(injectComponentDemo.class);
        setName("panel");      
       
        JLabel label = new JLabel();
        label.setName("label");       
        //resource.injectComponent(label);
       
       JButton button = new JButton();       
        button.setName("button");  
        //resource.injectComponent(button);
       
        add(label);
        add(button);
        resource.injectComponents(this);     
    }
}


.properties檔案內容如下:
 panel.opaque = true
 panel.background = 0,255,133

 button.text = hello world!
 button.foreground = 233,33,33
 button.background = 44,22,167

 label.text = hello world!
 label.opaque = true
 label.foreground = 100,55,66
 label.background = 77,22,222

 

迴響:

發表迴響:
迴響功能已被關閉