前回に引き続き、FXMLの利用法について確認していく。今回は多言語対応のために使われるリソース・バンドル、そしてコンポーネントの部品化を可能にするカスタム・コンポーネントの利用法を見ていく。
■ リソース・バンドルの利用
FXMLで多言語対応をしたい場合にはリソース・バンドル(ResourceBundleクラス)が利用できる。リソース・バンドルはJavaの標準クラスの1つで、地域別のメッセージをそれぞれファイル(*.properties)にまとめておくことで、実行環境のロケールに合わせたメッセージを出力する仕組みである。
指定するロケールにより、使用するリソース・ファイルが変更される。使用されるファイル名は、以下の3つの中でより上に存在するファイル名が適用される。言語名・国名はLocaleクラスで指定する2文字のコードである(
*1,
*2)。よく使うロケールを表1に示す。
- (基底名)_(指定ロケールの言語名)_(指定ロケールの国名).properties
- (基底名)_(指定ロケールの言語名).properties
- (基底名.properties」
表1:基底名「TestFXML2」に対してロケールを指定した場合に使用されるリソース・ファイルの名称
ロケール |
ファイル名 |
指定なし |
TestFXML2.properties |
Locale.JAPAN |
TestFXML2_jp_JP.properties
TestFXML2_jp.properties |
Locale.US |
TestFXML2_en_US.properties
TestFXML2_en.properties |
■ サンプルプログラム
リソース・バンドルを利用するサンプルを以下に示す。サンプルではロケールに日本を選ぶことで、日本語のpropertiesファイルを使用している。
◇リソース
TestJavaFX(プロジェクト)
┗ src
┣ application
┃ ┣ TestFXML4.java
┃ ┗ TestFXML4.fxml
┣ TestFXML4_en.properties
┗ TestFXML4_ja.properties
◇サンプルコード
【TestFXML4.java】
package application;
import java.net.URL;
import java.util.Locale;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* FXMLファイルを利用する4
*
* @author karura
*
*/
public class TestFXML4 extends Application
{
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception
{
// フォント色がおかしくなることへの対処
System.setProperty( "prism.lcdtext" , "false" );
// FXMLファイルの読込
URL location = getClass().getResource( "TestFXML4.fxml" );
ResourceBundle resources = ResourceBundle.getBundle( "TestFXML4" , Locale.JAPAN );
//ResourceBundle resources = ResourceBundle.getBundle( "TestFXML4" , Locale.US );
FXMLLoader fxmlLoader = new FXMLLoader( location , resources );
// シーングラフの作成
fxmlLoader.setRoot( new VBox() );
Pane root = (Pane) fxmlLoader.load();
// シーンの作成
Scene scene = new Scene( root , 200 , 40 );
// ウィンドウ表示
primaryStage.setScene( scene );
primaryStage.show();
}
}
【TestFXML4.fxml】
<?xml version="1.0" encoding="UTF-8"?>
<?language javascript?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml/1">
<children>
<!-- 変数宣言 -->
<!-- リソース・バンドルの利用例 -->
<Label fx:id="greeting" text="%message.greeting"/>
</children>
</fx:root>
【TestFXML4_en.properties】
# 英語のメッセージ
message.greeting=hello
【TestFXML4_ja.properties】
# 日本語のメッセージ
message.greeting=こんにちは
◇実行結果
◇解説
リソースバンドルの使用はTestFXML4.javaの34行目~36行目である。ResourceBundle::getBundle関数で、propertiesファイルの基底名とロケールを指定し、戻り値をFXMLLoaderの引数と渡すだけで、適切なpropertiesファイルが選ばれる。
propertiesファイルに記述されたリソースを出力しているのは、TestFXML4.fxmlの11行目である。「%」接頭辞によりリソース使用を宣言し、続いてリソース名「message.greeting」を指定している。TestFXML4_ja.propertiesファイルを見てみると、該当のキーに対して値は「こんにちは」となっており、これが画面出力されている。propertiesファイルの書き方はstruts等と同じなので見覚えがある人も多いと思われる。基本的に「key=value」を羅列しているだけである。
ちなみに、ResourceBundle::getBundle関数使用時にロケールをアメリカにする(TestFXML4.java:35行目の記述内容)と以下のような出力となり、propertiesファイルが正常に切り替わっていることが確認できる。
■ カスタム・コンポーネントの利用
FXMLではカスタム・コンポーネントにより、画面とコントローラを部品化することができる。カスタム・コンポーネントの作り方は、FXMLにて部品化したい画面構成を作成し、ルートタグをfx:rootタグに置き換え、コントローラ内でfx:rootタグをコントローラ自身にマッピングするだけでいい。こうして作成されたコントローラは、別のFXMLにて<?import>タグで取り込むことが可能となる。タグ名はコントローラのクラス名になる。
■ サンプルプログラム
カスタム・コンポーネントを作成・利用するサンプルプログラムを以下に示す。
◇リソース
TestJavaFX(プロジェクト)
┗ src
┗ application
┣ CustomTag.java
┣ TestFXML5.java
┣ CustomTag.fxml
┗ TestFXML5.fxml
◇サンプルコード
【TestFXML5.java】
package application;
import java.net.URL;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
/**
* FXMLファイルを利用する5
*
* @author karura
*
*/
public class TestFXML5 extends Application
{
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception
{
// フォント色がおかしくなることへの対処
System.setProperty( "prism.lcdtext" , "false" );
// FXMLファイルの読込
URL location = getClass().getResource( "TestFXML5.fxml" );
FXMLLoader fxmlLoader = new FXMLLoader( location );
// シーングラフの作成
Pane root = (Pane) fxmlLoader.load();
// シーンの作成
Scene scene = new Scene( root , 200 , 50 );
// ウィンドウ表示
primaryStage.setScene( scene );
primaryStage.show();
}
}
【TestFXML5.fxml】
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import application.CustomTag?>
<VBox xmlns:fx="http://javafx.com/fxml/1">
<Label text="hello world!" />
<CustomTag />
</VBox>
【CustomTag.java】
package application;
import java.io.IOException;
import java.net.URL;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.HBox;
/**
* TestFXML5.fxmlのコントローラ
*
* @author karura
*
*/
public class CustomTag extends HBox
{
/**
* デフォルト・コンストラクタ
*/
public CustomTag()
{
// 親のコンストラクタを起動
super();
// FXMLファイルの読込準備
URL location = getClass().getResource( "CustomTag.fxml" );
FXMLLoader fxmlLoader = new FXMLLoader( location );
// FXMLのルートタグとして、自らを登録
fxmlLoader.setRoot( this );
fxmlLoader.setController( this );
// FXMLの読込
try{
fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException( e.getMessage() );
}
// インスタンス化の確認メッセージ
System.out.println("CustomTag instantiation!");
}
/**
* Button1押下時のイベントハンドラ
* @param e
*/
@FXML
public void onPushButton1( ActionEvent e )
{
System.out.println( "button1 was pushed!" );
}
}
【CustomTag.fxml】
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<fx:root type="javafx.scene.layout.HBox" xmlns:fx="http://javafx.com/fxml/1">
<TextField fx:id="text1" promptText="input your name" />
<Button fx:id="button1" onAction="#onPushButton1" text="push"/>
</fx:root>
◇実行結果
CustomTag instantiation!
◇解説
プログラムは、TestFXML5クラスを起動しFXMLLoader::load関数でTestFXML5.fxmlを読み込むところから始まる。読み込まれたTestFXML5.fxml内では、5行目で新しく作成したカスタム・コンポーネントの宣言を、9行目で新しく作成したカスタム・コンポーネントを使用している。
TestFXML5.fxml内でCustomTagタグが呼ばれたことにより、CustomTagクラスがインスタンス化される(CustomTag.java:23行目~47行目)。コンストラクタ内部では、CustomTag.fxmlが読み込まれ、HBoxを継承したCustomTagクラスがルートノードに設定される(CustomTag.java:33行目)。同時にコントローラとしても登録することで、CustomTag.fxmlで作成されたボタンなどのオブジェクトやイベント・ハンドラとマッピングが行われている(CustomTag.java:34行目)。
そして、CustomTagタグの読み込みが完了し、TestFXML5.fxml自体の読み込みも完了するカスタム・コンポーネントであるCustomTag(テキスト入力欄とボタン)が画面に表示されていることが確認できる。「push」ボタンを押下すると、イベントハンドラCustomTag::onPushButton1(CustomTag.java:54行目~57行目)が起動され、標準出力に文字が出力されることが確認できる。
例えば、このCustomTagタグを配布する場合には、CustomTag.javaとCustomTag.fxmlの両方を配布すればよい。
■ 参照
- JavaDoc「クラス ResourceBundle - getBundle」
- JavaDoc「クラス Locale」
- Vladislav Korecký「How to create JavaFX FXML custom component」