JavaFxの紹介

JavaFxの概要

1. 前書き

JavaFXは、Javaでリッチクライアントアプリケーションを構築するためのライブラリです。 Javaをサポートするほぼすべてのデバイスで実行されるIt provides an API for designing GUI applications

このチュートリアルでは、その主要な機能のいくつかに焦点を当てて説明します。

2. JavaFX API

Java 8、9、および10では、JavaFXライブラリの操作を開始するために追加のセットアップは必要ありません。 JDK 11以降、プロジェクトはJDKから削除されます。

2.1. 建築

JavaFX uses hardware accelerated graphics pipeline for the rendering, known as Prism。 さらに、グラフィックスの使用を完全に加速するために、DirectXOpenGLを内部的に使用することにより、ソフトウェアまたはハードウェアのレンダリングメカニズムを活用します。

JavaFX has a platform dependent Glass windowing toolkit layer to connect to the native operating system。 オペレーティングシステムのイベントキューを使用して、スレッドの使用をスケジュールします。 また、ウィンドウ、イベント、タイマーを非同期に処理します。

MediaおよびWebエンジンは、メディアの再生とHTML / CSSのサポートを有効にします。

JavaFXアプリケーションのmain structureがどのように見えるかを見てみましょう。

image

 

ここでは、2つの主要なコンテナに注目します。

  • Stage is the main container and the entry point of the application。 これはメインウィンドウを表し、start()メソッドの引数として渡されます。

  • Sceneは、画像ビュー、ボタン、グリッド、テキストボックスなどのUI要素を保持するためのコンテナです。

Sceneは、別のSceneに置き換えるか切り替えることができます。 これは、Sceneグラフとして知られる階層オブジェクトのグラフを表します。 その階層内の各要素はノードと呼ばれます。 単一のノードには、ID、スタイル、効果、イベントハンドラー、状態があります。

さらに、Sceneには、レイアウトコンテナ、画像、メディアも含まれます。

2.2. スレッド

システムレベルでは、the JVM creates separate threads for running and rendering the application

  • Prismレンダリングスレッド–Scene Graphを個別にレンダリングします。

  • アプリケーションスレッド– JavaFXアプリケーションのメインスレッドです。 すべてのライブノードとコンポーネントはこのスレッドに接続されます。

2.3. ライフサイクル

javafx.application.Applicationクラスには、次のライフサイクルメソッドがあります。

  • init() – is called after the application instance is created。 この時点では、JavaFX APIの準備がまだ整っていないため、ここでグラフィカルコンポーネントを作成することはできません。

  • start(Stage stage) –すべてのグラフィカルコンポーネントがここに作成されます。 また、the main thread for the graphical activities starts here.

  • stop() –アプリケーションがシャットダウンする前に呼び出されます。たとえば、ユーザーがメインウィンドウを閉じたときです。 アプリケーションが終了する前に、クリーンアップのためにこのメソッドをオーバーライドすると便利です。

静的launch()メソッドは、JavaFXアプリケーションを起動します。

2.4. FXML

JavaFXは、特別なFXMLマークアップ言語を使用してビューインターフェイスを作成します。

これにより、ビューをビジネスロジックから分離するためのXMLベースの構造が提供されます。 XMLは、Scene Graph階層を非常に自然に表すことができるため、ここではより適しています。

最後に、.fxmlファイルをロードするために、FXMLLoaderクラスを使用します。これにより、シーン階層のオブジェクトグラフが作成されます。

3. 入門

実用的にするために、そしてlet’s build a small application that allows searching through a list of people.

まず、ドメインを表すために、Personモデルクラスを追加しましょう。

public class Person {
    private SimpleIntegerProperty id;
    private SimpleStringProperty name;
    private SimpleBooleanProperty isEmployed;

    // getters, setters
}

int, Stringbooleanの値をまとめるために、javafx.beans.propertyパッケージのSimpleIntegerProperty, SimpleStringProperty, SimpleBooleanPropertyクラスを使用していることに注意してください。

次に、Application抽象クラスを拡張するMainクラスを作成しましょう。

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(
          Main.class.getResource("/SearchController.fxml"));
        AnchorPane page = (AnchorPane) loader.load();
        Scene scene = new Scene(page);

        primaryStage.setTitle("Title goes here");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

メインクラスは、プログラムのエントリポイントであるstart()メソッドをオーバーライドします。

次に、FXMLLoaderは、オブジェクトグラフ階層をSearchController.fxmlからAnchorPaneにロードします。

新しいSceneを開始した後、それをプライマリStageに設定します。 また、ウィンドウのタイトルとshow()を設定します。

JavaFX LauncherなしでJARファイルを実行できるようにするには、main()メソッドを含めると便利です。

3.1. FXMLビュー

それでは、SearchControllerXMLファイルについて詳しく見ていきましょう。

検索アプリケーションでは、キーワードと検索ボタンを入力するためのテキストフィールドを追加します。


    

        
            
                

AnchorPaneは、ここではルートコンテナであり、グラフ階層の最初のノードです。 ウィンドウのサイズを変更するときに、子をアンカーポイントに再配置します。 The fx: controller attribute wires the Java class with the markup.

他にも利用可能な組み込みレイアウトがいくつかあります。

  • BorderPane –レイアウトを上、右、下、左、中央の5つのセクションに分割します

  • HBox –は、子コンポーネントを水平パネルに配置します

  • VBox –子ノードは垂直列に配置されます

  • GridPane –行と列を持つグリッドを作成するのに便利

この例では、水平方向のHBoxパネル内で、Labelを使用してテキストを配置し、TextFieldを入力に使用し、Buttonを使用しました。 fx: idを使用して要素にマークを付け、後でJavaコードで使用できるようにします。

次に、それらをJavaフィールドにマップするために–@FXMLアノテーションを使用します。

public class SearchController {

    @FXML
    private TextField searchField;
    @FXML
    private Button searchButton;

    @FXML
    private void initialize() {
        // search panel
        searchButton.setText("Search");
        searchButton.setOnAction(event -> loadData());
        searchButton.setStyle("-fx-background-color: #457ecd; -fx-text-fill: #ffffff;");
    }
}

After populating the @FXML annotated fields, initialize() will be called automatically.ここでは、イベントリスナーの登録、スタイルの追加、テキストプロパティの変更など、UIコンポーネントに対してさらにアクションを実行できます。

最後に、ここで説明するこのロジックはすべて、次のウィンドウを生成します。

image

4. Binding API

視覚的な側面が処理されたので、バインディングデータを見てみましょう。

バインディングAPIは、別のオブジェクトの値が変更されたときにオブジェクトに通知するいくつかのインターフェースを提供します。

bind()メソッドを使用するか、リスナーを追加することにより、値をバインドできます。

単方向バインディングは、一方向のバインディングのみを提供します。

searchLabel.textProperty().bind(searchField.textProperty());

ここで、検索フィールドを変更すると、ラベルのテキスト値が更新されます。

比較すると、双方向バインディングは、2つのプロパティの値を両方向に同期します。

フィールドをバインドする別の方法はChangeListeners:です

searchField.textProperty().addListener((observable, oldValue, newValue) -> {
    searchLabel.setText(newValue);
});

Observableインターフェースを使用すると、オブジェクトの値の変更を監視できます。

これを例証するために、最も一般的に使用される実装はjavafx.collections.ObservableList<T>インターフェースです。

ObservableList masterData = FXCollections.observableArrayList();

ここでは、要素の挿入、更新、削除などのモデルの変更は、UIコントロールにすぐに通知されます。

5. 並行性

Working with the UI components in a scene graph isn’t thread-safe, as it’s accessed only from the Application thread.javafx.concurrentパッケージは、マルチスレッド化を支援するためにここにあります。

バックグラウンドスレッドでデータ検索を実行する方法を見てみましょう。

Task> task = new Task>() {
    @Override
    protected ObservableList call() throws Exception {
        updateMessage("Loading data");
        return FXCollections.observableArrayList(masterData
          .stream()
          .filter(value -> value.getName().toLowerCase().contains(searchText))
          .collect(Collectors.toList()));
    }
};

ここでは、1回限りのタスクjavafx.concurrent.Taskオブジェクトを作成し、call()メソッドをオーバーライドします。

The call() method runs entirely on the background thread and returns the result to the Application thread.これは、このメソッド内でUIコンポーネントを操作すると、ランタイム例外がスローされることを意味します。

ただし、updateProgress(), updateMessage()を呼び出して、アプリケーションスレッドアイテムを更新できます。 タスクの状態がSUCCEEDED状態に移行すると、onSucceeded()イベントハンドラーがアプリケーションスレッドから呼び出されます。

task.setOnSucceeded(event -> {
    masterData = task.getValue();
    // update other UI components
});

TaskRunnableであるため、開始するには、taskパラメータを使用して新しいThreadを開始する必要があります。

Thread th = new Thread(task);
th.setDaemon(true);
th.start();

setDaemon(true)フラグは、作業の終了後にスレッドが終了することを示します。

6. イベント処理

イベントは、アプリケーションにとって興味深いアクションであると説明できます。

たとえば、マウスクリック、キー押下、ウィンドウサイズ変更などのユーザーアクションは、javafx.event.Eventクラスまたはそのサブクラスのいずれかによって処理または通知されます。

また、3種類のイベントを区別します。

  • InputEventKEY_PRESSED, KEY_TYPED, KEY_RELEASEDMOUSE_PRESSES, MOUSE_RELEASEDなどのすべてのタイプのキーおよびマウスアクション

  • ActionEventButtonの起動やKeyFrameの終了などのさまざまなアクションを表します

  • WindowEventWINDOW_SHOWING, WINDOW_SHOWN

実例を示すために、以下のコードフラグメントは、searchField上でEnterキーを押すイベントをキャッチします。

searchField.setOnKeyPressed(event -> {
    if (event.getCode().equals(KeyCode.ENTER)) {
        //search and load some data
    }
});

7. スタイル

カスタムデザインを適用することで、JavaFXアプリケーションのUIを変更できます。

デフォルトでは、JavaFXはアプリケーション全体のCSSリソースとしてmodena.cssを使用します。 これはjfxrt.jarの一部です。

デフォルトのスタイルをオーバーライドするには、シーンにスタイルシートを追加できます。

scene.getStylesheets().add("/search.css");

インラインスタイルも使用できます。たとえば、特定のノードのスタイルプロパティを設定するには:

searchButton.setStyle("-fx-background-color: slateblue; -fx-text-fill: white;");

8. 結論

この短い記事では、JavaFX APIの基本について説明します。 内部構造を調べ、そのアーキテクチャ、ライフサイクル、およびコンポーネントの主要な機能を紹介しました。

その結果、簡単なGUIアプリケーションを学習し、作成できるようになりました。

そして、いつものように、チュートリアルの完全なソースコードはover on GitHubで利用できます。