0

この質問では、ラッピングオブジェクトを変更し、変更された更新を送信しないことで、プロパティが変更されるという問題に対処する方法を示しました。解決策はReactFXを使用していました:

class Cell {

    private final ObjectProperty<Shape> shape = new SimpleObjectProperty<>(new Shape());
    // all getters and setterts

    public static class Shape {

        private final IntegerProperty size = new SimpleIntegerProperty(0);
        // all getters and setterts
    }

    public static void main(String[] args) {

        Var<Number> sizeVar = Val.selectVar(cell.shapeProperty(), Shape::sizeProperty);
        sizeVar.addListener(
            (obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));
}

したがって、shapeプロパティ自体が変更されると、変更もトリガーされsizeます (新しい形状が同じサイズでない限り)。しかし、カスタムバインディングを使用してプロパティにバインドしたいのですが、以下で説明する問題があります。

私のデータクラスは次のとおりです。

class Cell {

    private final ObjectProperty<Shape> shape = new SimpleObjectProperty<>();
    public final ObjectProperty<Shape> shapeProperty() { return shape; }
    public final Shape getShape()                      { return shapeProperty().get(); }
    public final void setShape(Shape shape)            { shapeProperty().set(shape); }

    // other properties
}

class Shape {

    private final IntegerProperty size = new SimpleIntegerProperty();
    public final IntegerProperty sizeProperty() { return size; }
    public final int getSize()                  { return size.get(); }
    public final void setSize(int size)         { sizeProperty().set(size); }

    // other properties
}

そして、それらのプロパティを GUI プロパティにバインドして、それらの GUI 表現を作成したいと考えています。私はこのようにします:

class CellRepresentation extends Group {

    private final Cell cell;

    CellRepresentation(Cell cell) {

        this.cell = cell;
        getChildren().add(new ShapeRepresentation() /*, other representations of things in the cell*/);
    }

    private class ShapeRepresentation extends Cylinder {

        ObjectProperty<Shape> shape;

        private ShapeRepresentation() {

            super(100, 100);

            shape = new SimpleObjectProperty<Shape>(cell.getShape());
            shape.bind(cell.shapeProperty());

            Var<Number> sizeVar = Val.selectVar(cell.shapeProperty(), Shape::sizeProperty);

            // THIS WILL WORK
            materialProperty().bind(Bindings.createObjectBinding(() -> {
                if (shape.get() == null)
                    return new PhongMaterial(Color.TRANSPARENT);
                return new PhongMaterial(Color.RED);
            }, sizeVar));

            // THIS WILL NOT WORK
            materialProperty().bind(sizeVar.map(n -> {
                if (shape.get() == null)
                    return new PhongMaterial(Color.TRANSPARENT);
                return new PhongMaterial(Color.RED);
            }));
        }
    }

    // the other representations of things in the cell
}

以下のコードを実行すると、バインドの最初のオプションによって透明な円柱が作成されます。2 番目のオプションは、白 (既定の色) の円柱を作成します。なぜこれが起こるのかわかりません。

public class Example extends Application {

    public static void main(String[] args) {

        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {

        Cell cell = new Cell();
        CellRepresentation cellRep = new CellRepresentation(cell);

        Group group = new Group(cellRep);
        Scene scene = new Scene(group, 200, 200, Color.AQUA);
        stage.setScene(scene);
        stage.show();
    }
}

また、バインディングを使用してデータ クラスの表現を作成する方法が適切でない場合は、設計に関する提案も受け付けています。

4

1 に答える 1

2

ValそしてVar「観察可能なモナド」です(観察可能なものを考えてくださいOptional)。それらは空であるか、値を保持しています。このmapメソッドは次のように機能します。が空Optional.mapの場合、空の;になります。それ以外の場合は、関数を元の の値に適用した結果を含む になります。したがって、 がに評価される場合、ラムダ式を評価することさえせずに、マッピングの結果は空になります (したがって、マテリアルは に設定されます)。ValmapValValValsizeVarnullValnull

null(空Valの s)を処理するには、orElseまたは同様の方法を使用する必要があります。

private class ShapeRepresentation extends Cylinder {

    Val<Shape> shape;

    private ShapeRepresentation() {

        super(100, 100);

        shape = Val.wrap(cell.shapeProperty());

        Var<Number> sizeVar = shape.selectVar(Shape::sizeProperty);

        // THIS WILL WORK

        materialProperty().bind(shape
            .map(s -> new PhongMaterial(Color.RED))
            .orElseConst(new PhongMaterial(Color.TRANSPARENT)));

        // SO WILL THIS

        materialProperty().bind(sizeVar
                .map(n -> {
                    if (n.intValue() == 1) return new PhongMaterial(Color.RED) ;
                    if (n.intValue() == 2) return new PhongMaterial(Color.BLUE) ;
                    return new PhongMaterial(Color.WHITE);
                })
                .orElseConst(new PhongMaterial(Color.TRANSPARENT)));

    }
}

テスト用に更新された例:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Example extends Application {

    public static void main(String[] args) {

        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {

        Cell cell = new Cell();

        CellRepresentation cellRep = new CellRepresentation(cell);

        Group group = new Group(cellRep);

        ComboBox<Integer> sizeCombo = new ComboBox<>();
        sizeCombo.getItems().addAll(0, 1, 2);

        Shape shape = new Shape();
        shape.sizeProperty().bind(sizeCombo.valueProperty());


        CheckBox showShape = new CheckBox("Show shape");
        cell.shapeProperty().bind(Bindings.when(showShape.selectedProperty()).then(shape).otherwise((Shape)null));

        HBox controls = new HBox(5, showShape, sizeCombo);
        controls.setPadding(new Insets(5));

        BorderPane root = new BorderPane(group, controls, null, null, null);
        root.setBackground(null);

        Scene scene = new Scene(root, 400, 400, Color.AQUA);
        stage.setScene(scene);
        stage.show();
    }
}
于 2017-01-11T01:04:14.000 に答える