LoginSignup
20
18

More than 5 years have passed since last update.

JavaFXのプロパティバインド

Last updated at Posted at 2016-04-24

JavaFXの概要

Java7から採用されたデスクトップUIです。
FXMLによるGUI構成の記述、CSSによるデザインの分離、Prismとよばれるハードウェアアクセラレーション対応の描画エンジン、WebKitベースのブラウザを搭載といったのが特徴ですが、Java界隈以外の人にはまったく知られていない感じがしますね。

JavaFXアーキテクチャ

グラフを含めてGUI部品は揃っていますし、アニメーションのためのタイムラインもあります。
しかし、ダイアログがなかったり、画面遷移のためのAPIもなかったり、入力値に対するバリデーション機能といったものがありませんので、足らない部分は自分で作り込む必要は出てきます。これらの話しはまた書きたくなったら書くとして、本記事ではJavaFXの基本とプロパティバインドについて書きます。

JavaFXの作業手順

画面の作り方は以下のどちらかを使い分けます。

  • FXMLで画面構成
  • APIを使って動的に生成

scene.png

FXMLはエディターで記述ができますが、Scene Builderというツールを使うのが楽です。メンテナンスや多人数開発を考えると直接記述はお勧めしません。
動的に生成するにはAPIを使うことになりますが、コンポーネント単位でScene Builderで作りこんでAPIで埋め込むといった手順を踏むべきでしょう。

FXMLには関連づくクラスを記載します。するとFXML読み込み時に自動的に生成されます。作りは見ていませんがコンテナ管理されているかもです。

Scene.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane"
            prefHeight="200"
            prefWidth="320"
            xmlns:fx="http://javafx.com/fxml/1"
            xmlns="http://javafx.com/javafx/8"
            fx:controller="com.exsample.javafxsample.FXMLController">
    <children>
        <Label fx:id="label" layoutX="77.0" layoutY="51.0" minHeight="16" minWidth="69" text="Label" />
        <Button layoutX="79.0" layoutY="108.0" onAction="#onAction" text="Button" />
        <TextField fx:id="nameField" layoutX="79.0" layoutY="75.0" />
    </children>
</AnchorPane>

Javaにはアノテーションという便利な仕組みがあるので、GUI部品との関連付けは一発ですね。

FXMLController.java
package com.exsample.javafxsample;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;

public class FXMLController implements Initializable {

    @FXML
    private Label label;
    @FXML
    private TextField nameField;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }    

    @FXML
    private void onAction(ActionEvent event) {
        label.setText(nameField.getText());
    }

}
MainApp.java
package com.exsample.javafxsample;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class MainApp extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/fxml/Scene.fxml"));
        Scene scene = new Scene(root);
        scene.getStylesheets().add("/styles/Styles.css");
        stage.setTitle("JavaFX and Maven");
        stage.setScene(scene);
        stage.show();
    }

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

}

是非覚えてほしいプロパティバインド

アノテーションでGUI部品に対してプロパティの読み込みや設定ができるのですが、どんなアプリケーションでもモデルとビューは切り分けたいものです。
で、モデルを分離したときにGUI部品に対していちいちSet/Getするのは格好が悪いのでやめましょう。プロパティバインドという仕組みがあります。モデルの値が変わればビューも変わりますし、UIの入力があればモデルの値も変わります。

ちなみにこのモデルは遅延バインドするためのコードになっています。
モデルがJAXBでXMLと相互変換したり、O/Rマッピングする場合は遅延バインドしましょう。

Modle.java
package com.exsample.javafxsample;

import java.util.Objects;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Model {

    private StringProperty valueProperty = null;
    private String value;

    public StringProperty valueProperty() {
        if (Objects.isNull(valueProperty)) {
            valueProperty = new SimpleStringProperty(value);
        }
        return valueProperty;
    }

    public String getValue() {
        if (Objects.nonNull(valueProperty)) {
            return valueProperty.get();
        }
        return value;
    }

    public void setValue(String value) {
        if (Objects.nonNull(valueProperty)) {
            valueProperty.set(value);
        } else {
            this.value = value;
        }
    }

}

コントローラクラスを書き換えます。
ボタンの役割は無視するとして、テキスト入力するとラベルを更新します。

FXMLController.java
public class FXMLController implements Initializable {

    private final Model model = new Model();
    @FXML
    private Label label;
    @FXML
    private TextField nameField;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        label.textProperty().bind(model.valueProperty());
        model.valueProperty().bind(nameField.textProperty());
    }    

    @FXML
    private void onAction(ActionEvent event) {
    }

}

実行例です。

application.png

20
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
18