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)方法,就可以設定某元件的屬性。
以上面的例子就是
label.setName("label");
類似這樣:
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檔裡面,定義好一些共用的資源,然後利用ApplicationContext及ResourceManager來取得。
先前提到在Swing Application Framework中,都是利用ApplicationContext來提供程式執行時的一些服務,取得資源就是其中一項。
ApplicationContext採用的是Design Pattern中的Singleton Pattern,所以不能直接建立實體,可以利用Application中提供的getContext()來取得ApplicationContext的實體。
然後在取得實體後, 就可以取得相對應的ResourceMap
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