第4章 JavaFX による GUI プログラミング : 問題 5 : ObservableValue とラムダ式
問題
次の二つのメソッドを実装せよ
public static <T,R> ObservableValue<R> observe(Function<T,R> f, ObservableValue<T> t) public static <T,U,R> ObservableValue<R> observe(BiFunction<T,U,R> f, ObservableValue<T> t, ObservableValue<U> u)
このメソッドは、与えられたObservableValue
のgetValue
メソッドをFunction
またはBiFunction
で変換する
そして、元のObservableValue
で Invalid イベントまたは Change イベントが起こったときは、observe
メソッドが生成したObservableValue
でもイベントが起こるようにせよ
ObservableValue について
もはや驚いたりはしないが、この本では本文に何の説明もないのに練習問題でいきなり登場することがある
ObservableValue<T>
は、本文で取り上げられたBinding<T>
とProperty<T>
の共通の祖先である
■ ObservableValue
つまりObservableValue
は Invalid イベントと Change イベントを受けられる Value である
解答
ゲージ(Rectangle)の長さとボタンが連動するサンプルソースで検証する
■ オリジナル
import static javafx.beans.binding.Bindings.*; public void start(Stage stage) throws Exception { Button smaller = new Button("Smaller"); Button larger = new Button("Larger"); Rectangle gauge = new Rectangle(0, 5, 50, 15); Rectangle outline = new Rectangle(0, 5, 100, 15); outline.setFill(null); outline.setStroke(Color.BLACK); Pane pane = new Pane(); pane.getChildren().addAll(gauge, outline); // ボタンクリック時のアクション smaller.setOnAction(event -> gauge.setWidth(gauge.getWidth() - 10)); larger .setOnAction(event -> gauge.setWidth(gauge.getWidth() + 10)); // ゲージの長さとボタンの有効/無効 smaller.disableProperty().bind(lessThanOrEqual( gauge.widthProperty(), 0)); larger .disableProperty().bind(greaterThanOrEqual(gauge.widthProperty(), 100)); HBox box = new HBox(10); box.getChildren().addAll(smaller, pane, larger); Scene scene = new Scene(box); stage.setScene(scene); stage.show(); }
これをobserve
メソッドを使って書き直す
■ observe
メソッドを使用
// ゲージの長さとボタンの有効/無効 smaller.disableProperty().bind( observe( t -> t.doubleValue() <= 0.0, gauge.widthProperty() ) ); larger.disableProperty().bind( observe( t -> t.doubleValue() >= 100.0, gauge.widthProperty() ) );
では、observe
メソッドを実装してみよう
■ observe
メソッドの実装
import static javafx.beans.binding.Bindings.*; public static <T,R> ObservableValue<R> observe(Function<T,R> f, ObservableValue<T> t) { return createObjectBinding( () -> f.apply(t.getValue()), t ); } public static <T,U,R> ObservableValue<R> observe(BiFunction<T,U,R> f, ObservableValue<T> t, ObservableValue<U> u) { return createObjectBinding( () -> f.apply(t.getValue(), u.getValue()), t, u ); }