6 JavaFXでのSwingアプリケーションの実装
この章では、Swingアプリケーションについて検討し、このアプリケーションをJavaFXで実装する方法について学習します。
この章の内容を理解するには、図6-1に示すConverter
アプリケーションに関する知識が必要です。このアプリケーションは、距離に関する測定値をメートル法と米国単位間で変換します。
Swingで開発したConverterアプリケーションの分析
Javaプログラミング言語を使用したこの例の実装の詳細は、Swingチュートリアルのパネルの使用方法に関するトレールおよびモデルの使用に関するトレールコースを参照してください。特に、グラフィカル・ユーザー・インタフェース(GUI)については、パネルに関するトレールを参照してください。
Converterアプリケーションのコードについて学習するには、例の索引から入手できる、このアプリケーションのNetBeansプロジェクトまたはソース・ファイルをダウンロードします。
Swingコンポーネントは、モデルを使用します。プロジェクトの内容を確認すると、Converterアプリケーションのモデルを定義するConverterRangeModel
およびFollowerRangeModel
クラスが含まれていることがわかります。
Converterアプリケーションは、次のファイルで構成されています。
-
ConversionPanel.java
: コンポーネントを保持するためのカスタムJPanel
サブクラスが含まれています。 -
Converter.java
: アプリケーションのメイン・クラスが含まれています。 -
ConverterRangeModel.java
: 上部のスライダのモデルを定義します。 -
FollowerRangeModel.java
: 下部のスライダのモデルを定義します。 -
Units.java
:Unit
オブジェクトを作成します。
各テキスト・フィールドとそのスライダ間の同期は、値の変更をリスニングするイベント・ハンドラによって実装されます。
JavaFXでのConverterアプリケーションの計画
Converter
アプリケーションには、テキスト・フィールド、スライダ、コンボ・ボックスなどのコンポーネントを保持する、類似した2つのパネルが含まれています。パネルにはタイトルがあります。javafx.scene.controlパッケージのTitlePane
クラスは、Converter
アプリケーションのGUIに最適です。
ここでは、ConversionPanel
クラスを実装し、このクラスの2つのインスタンスをConverter
アプリケーションのグラフィカル・シーンに追加します。
まず、1つのConversionPanel
オブジェクト内のコンポーネントを、次のように同期する必要があります。スライダ上のノブを動かすたびにテキスト・フィールドの値を更新し、その逆も同様にする必要があります。つまり、テキスト・フィールドの値を変更するたびにスライダ上のノブの位置を調整する必要があります。
コンボ・ボックスから別の値を選択するとすぐにテキスト・フィールドの値を更新し、それに伴いスライダ上のノブの位置も更新する必要があります。
2番目に、両方のConversionPanel
オブジェクトを同期する必要があります。1つのパネル上で変更が発生するとすぐに、別のパネル上の対応するコンポーネントを更新する必要があります。
meters
というDoubleProperty
オブジェクトを使用してパネル間の同期を実装し、fromMeters
とtoMeters
という2つのInvalidationListener
オブジェクトを作成および登録することによって、テキスト・フィールドとコンボ・ボックスのプロパティ内の変更をリスニングすることをお薦めします。1つのパネル上のテキスト・フィールドのプロパティが変更されるたびに、アタッチされたInvalidationListener
オブジェクトのinvalidated
メソッドがコールされ、meters
プロパティが更新されます。meters
プロパティが変更されるため、meters
プロパティにアタッチされたInvalidationListener
オブジェクトのinvalidated
メソッドがコールされ、別のパネル上の対応するテキストが更新されます。
同様に、1つのパネル上のコンボ・ボックスのプロパティが変更されるたびに、アタッチされたInvalidationListener
オブジェクトのinvalidated
メソッドがコールされ、このパネル上のテキスト・フィールドが更新されます。
スライダの値とmeters
オブジェクトの値が同期されるようにするには、双方向バインディングを使用します。
JavaFXプロパティとバインディングの詳細は、「JavaFXプロパティとバインディングの使用」を参照してください。
JavaFXでのConverterアプリケーションの作成
NetBeans IDEで新しいJavaFXプロジェクトを作成し、Converterという名前を付けます。Unit.java
ファイルをSwingアプリケーションからConverterプロジェクトにコピーします。新しいjavaクラスをこのプロジェクトに追加し、ConversionPanel.java
という名前を付けます。
GUIを作成するための標準的なJavaFXパターン
JavaFXでのConverter
アプリケーションのGUIの作成を開始する前に、例6-1に示す、SwingアプリケーションでのGUIの標準的な作成パターンを確認します。
例6-1
public class Converter { private void initAndShowGUI() { ... } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { initAndShowGUI(); } }); } }
このパターンをJavaFXにマップするには、例6-2に示すように、javafx.application.Application
クラスを拡張し、start
メソッドをオーバーライドし、main
メソッドをコールします。
例6-2
import javafx.application.Application; import javafx.stage.Stage; public class Converter extends Application { @Override public void start(Stage t) { ... } public static void main(String[] args) { launch(args); } }
NetBeans IDEで新しいJavaFXプロジェクトを作成すると、このパターンが自動的に生成されます。ただし、特にテキスト・エディタを使用する場合は、JavaFXでのGUI作成の基本的なアプローチを理解しておくことが重要です。
コンテナおよびレイアウト
Swingでは、コンテナおよびレイアウト・マネージャは異なるエンティティです。JPanel
オブジェクト、JComponent
オブジェクトなどのコンテナを作成し、このコンテナのレイアウト・マネージャを設定します。特定のレイアウト・マネージャを割り当て、コード内に.add()
を記述することも、レイアウト・マネージャを割り当てないようにすることもできます。
JavaFXでは、コンテナ自体がその子ノードのレイアウトを処理します。Vbox
オブジェクト、FlowPane
オブジェクト、TitledPane
オブジェクトなどの特定のレイアウト・ペインを作成した後、.getChildren().add()
メソッドを使用して、コンテンツをその子ノードのリストに追加します。
JavaFXには、ペインと呼ばれる様々なレイアウト・コンテナ・クラスがあり、その一部に対応するクラスがSwingでも提供されています。たとえば、JavaFXのFlowPane
クラスは、SwingのFlowLayout
クラスに対応しています。
詳細は、JavaFXでのレイアウトの操作を参照してください。
UIコントロール
JavaFX SDKでは、標準的なUIコントロールのセットが提供されます。一部のUIコントロールは、Swingのコントロールと対応しています。たとえば、JavaFXのButton
クラスとSwingのJButton
、JavaFXのSlider
とSwingのJSlider
、およびJavaFXのTextField
とSwingのJTextField
があります。
JavaFXでConverter
アプリケーションを実装する場合、TextField
、Slider
およびComboBox
クラスによって提供される標準的なUIコントロールを使用できます。
詳細は、「JavaFX UIコントロールの使用」を参照してください。
ユーザー・アクションとバインディングに基づいて通知を取得するメカニズム
Swingでは、任意のコンポーネントにリスナーを登録し、サイズ、位置、可視性などのコンポーネント・プロパティの変更をリスニングしたり、コンポーネントにキーボード・フォーカスがあるかないか、マウスをコンポーネント上でクリックする、押す、離すなどのイベントをリスニングできます。
JavaFXでは、リスナーを登録できるプロパティのセットがオブジェクトごとに提供されます。このリスナーは、プロパティの値を変更するたびにコールされます。
オブジェクトは、別のオブジェクトのプロパティにおける変更のリスナーとして登録できることに注意してください。このため、バインディング・メカニズムを使用すると、2つのオブジェクトの一部のプロパティを同期できます。
ConversionPanelクラスの作成
ConversionPanel
クラスは、テキスト・フィールド、スライダ、コンボ・ボックスなどのコンポーネントを保持するために使用します。Converter
アプリケーションのグラフィカル・シーンを作成するときに、ConversionPanel
クラスの2つのインスタンスをこのグラフィカル・シーンに追加します。例6-3に示すように、TitledPane
クラスのimport文を追加し、ConversionPanel
クラスを拡張します。
UIコントロールのインスタンス変数の作成
例6-4に示すように、TextField
、Slider
およびComboBox
コントロールのimport文を追加し、これらのコンポーネントのインスタンス変数を定義します。
DoublePropertyおよびNumberFormatオブジェクトの作成
例6-5に示すように、DoubleProperty
およびNumberFormatクラスのimport文を追加し、meters
という名前のDoubleProperty
オブジェクトを作成します。meters
オブジェクトは、2つのConversionPanel
オブジェクト間の同期を確保するために使用します。
コンポーネントのレイアウト
テキスト・フィールドとスライダのレイアウトを行うには、VBox
クラスを使用します。これらのコンポーネントとコンボ・ボックスの両方のレイアウトを行うには、HBox
クラスを使用します。例6-6に示すように、ObservableList
クラスのimport文を追加し、ConversionPanel
クラスのコンストラクタを実装します。
例6-6
import javafx.collections.ObservableList; public ConversionPanel(String title, ObservableList<Unit> units, DoubleProperty meters) { setText(title); setCollapsible(false); numberFormat = NumberFormat.getNumberInstance(); numberFormat.setMaximumFractionDigits(2); textField = new TextField(); slider = new Slider(0, MAX, 0); comboBox = new ComboBox(units); comboBox.setConverter(new StringConverter<Unit>() { @Override public String toString(Unit t) { return t.description; } @Override public Unit fromString(String string) { throw new UnsupportedOperationException("Not supported yet."); } }) VBox vbox = new VBox(textField, slider); HBox hbox = new HBox(vbox, comboBox); setContent(hbox); this.meters = meters; comboBox.getSelectionModel().select(0); }
コードの最終行は、ComboBox
オブジェクト内の値を選択しています。
InvalidationListenerオブジェクトの作成
テキスト・フィールドとコンボ・ボックスのプロパティにおける変更をリスニングするには、例6-7に示すように、fromMeters
とtoMeters
というInvalidationListener
オブジェクトを作成します。
例6-7
import javafx.beans.InvalidationListener; private InvalidationListener fromMeters = t -> { if (!textField.isFocused()) { textField.setText(numberFormat.format(meters.get() / getMultiplier())); } }; private InvalidationListener toMeters = t -> { if (!textField.isFocused()) { return; try { meters.set(numberFormat.parse(textField.getText()).doubleValue() * getMultiplier()); } catch (ParseException | Error | RuntimeException ignored) { } };
コントロールへの変更リスナーの追加と同期の確保
テキスト・フィールドとコンボ・ボックス間が同期されるようにするには、例6-8に示すように、変更リスナーを追加します。
例6-8
meters.addListener(fromMeters); comboBox.valueProperty().addListener(fromMeters); textField.textProperty().addListener(toMeters); fromMeters.invalidated(null);
例6-9に示すように、スライダの値とmeters
オブジェクトの値間の双方向バインディングを作成します。
新しい値をテキスト・フィールドに入力すると、toMeters
リスナーのinvalidated
メソッドがコールされ、meters
オブジェクトの値が更新されます。
Converterクラスの作成
NetBeans IDEによって自動的に生成されたConverter.java
ファイルを開き、main
メソッド以外のすべてのコードを削除します。その後、[Ctrl] (または[Cmd])キーと[Shift]キーを押しながら[I]キーを押して、import文を修正します。
インスタンス変数の定義
例6-10に示すように、ObservableList
、DoubleProperty
およびSimpleDoubleProperty
クラスのimport文を追加し、適切な型のmetricDistances
、usaDistances
およびmeters
変数を作成します。
Converterクラスのコンストラクタの作成
例6-11に示すように、Converter
クラスのコンストラクタで、メートル法の距離と米国単位の距離に対応するUnit
オブジェクトを作成します。FXCollections
クラスのimport文を追加します。後から、これらの単位を使用して2つのConversionPanel
オブジェクトをインスタンス化します。
例6-11
import javafx.collections.FXCollections; public Converter() { metricDistances = FXCollections.observableArrayList( new Unit("Centimeters", 0.01), new Unit("Meters", 1.0), new Unit("Kilometers", 1000.0)); usaDistances = FXCollections.observableArrayList( new Unit("Inches", 0.0254), new Unit("Feet", 0.305), new Unit("Yards", 0.914), new Unit("Miles", 1613.0)); }
グラフィカル・シーンの作成
Converter
アプリケーションのグラフィカル・シーンを作成するには、start
メソッドをオーバーライドします。2つのConversionPanel
オブジェクトをグラフィカル・シーンに追加し、これらを垂直方向にレイアウトします。2つのConversionPanel
オブジェクトが、同じmeters
オブジェクトを使用してインスタンス化されていることに注意してください。グラフィカル・シーンのルート・コンテナには、VBox
クラスを使用します。例6-12に示すように、2つのConversionPanel
オブジェクトをインスタンス化します。
例6-12
@Override public void start(Stage stage) { VBox vbox = new VBox( new ConversionPanel( "Metric System", metricDistances, meters), new ConversionPanel( "U.S. System", usaDistances, meters)); Scene scene = new Scene(vbox); stage.setTitle("Converter"); stage.setScene(scene); stage.show(); }
このドキュメントの一番下にあるリンクを使用して、JavaFXでのConverter
アプリケーションのソース・コードを参照したり、このアプリケーションのNetBeansプロジェクトをダウンロードできます。
図6-2に、JavaFXでのConverterアプリケーションを示します。
SwingライブラリとJavaFXを使用して同じ機能を実装した2つのアプリケーションを比較してみてください。
JavaFXアプリケーションに含まれるファイルが3つであるのに対して、Swingアプリケーションのファイルは5つであり、さらにJavaFXコードの方がすっきりしています。アプリケーションのルック・アンド・フィールも異なります。