属性属性有意义吗?

时间:2016-11-08 19:28:18

标签: java javafx javafx-2 reactfx

因为这是一个关于设计的问题,我首先会说出我拥有的和我想要的东西。

我有使用合成的设计。 Cell对象包含ShapeBackground个对象(此示例为自定义对象)。这两个中的每一个都有自己的数据来定义它们。这是代码中的示例:

class Cell {

    Shape shape;
    Background background;

    class Shape {

        int size;
        Color color;
        Point location;
        //...
    }

    class Background {

        Color color;
        String name;
        CoverType type;
        //...
    }
}

我还有一个需要代表许多单元格的GUI,我已经写了如何做(如何使用颜色,大小等来创建我想要的屏幕)。它包括CellRepresentation,ShapeRepresentation和BackgroundRepresentation等类,它们的显示属性绑定到数据属性(我认为这称为模型和视图)。

我希望能够通过更改上述数据来表示GUI中的更改:

  • 用户可以(例如)右键单击形状并设置其颜色。因此,上述数据发生变化,需要在GUI中反映出变化。
  • 用户还可以更改整个形状(例如,从另一个单元格中复制粘贴)。甚至整个细胞。这些变化也需要反映在GUI中。

我的问题是哪个类成员需要是我绑定的JavaFX属性。

这就是我的想法:" leaf"属性(大小,颜色,位置......)必须是属性,因此我可以将GUI属性绑定到它们。但是我还需要制作形状和背景对象属性吗?只有他们的财产有"实际"屏幕上的表示。理想情况下,我会喜欢它,如果Shape发生变化,那么它的所有属性都会告诉它们的绑定它们可能已经改变了(可能颜色没有,但尺寸确实如此)。但它不会以这种方式工作 - 即使Shape变化时Color的颜色也会改变Color属性不会告诉它改变了什么绑定它。 / p>

同样适用于在较大的图片中制作Cell属性,其中有许多单元格等等:属性委托更改的属性。

所以我想到了使Shape和Background属性并向它们注册InvalidationListener来更新它们的属性。这看起来并不合适,因为我认为,只要拥有对物业的所有支持,就有办法做我想做的事。

有人可以建议一种方法吗?

1 个答案:

答案 0 :(得分:3)

仅使用标准JavaFX API,您可以利用Bindings.selectXXX方法观察属性的属性"。

例如:

import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.paint.Color;

public class Cell {

    private final ObjectProperty<Shape> shape = new SimpleObjectProperty<>(new Shape());


    public final ObjectProperty<Shape> shapeProperty() {
        return this.shape;
    }




    public final Cell.Shape getShape() {
        return this.shapeProperty().get();
    }




    public final void setShape(final Cell.Shape shape) {
        this.shapeProperty().set(shape);
    }


    public static class Shape {

        private final IntegerProperty size = new SimpleIntegerProperty(0);
        private final ObjectProperty<Color> color = new SimpleObjectProperty<>(Color.BLACK);
        public final IntegerProperty sizeProperty() {
            return this.size;
        }

        public final int getSize() {
            return this.sizeProperty().get();
        }

        public final void setSize(final int size) {
            this.sizeProperty().set(size);
        }

        public final ObjectProperty<Color> colorProperty() {
            return this.color;
        }

        public final javafx.scene.paint.Color getColor() {
            return this.colorProperty().get();
        }

        public final void setColor(final javafx.scene.paint.Color color) {
            this.colorProperty().set(color);
        }

    }


    public static void main(String[] args) {
        Cell cell = new Cell();
        Bindings.selectInteger(cell.shapeProperty(), "size").addListener(
                (obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));
        cell.getShape().setSize(10);
        cell.setShape(new Shape());
        Shape s = new Shape();
        s.setSize(20);
        cell.setShape(s);
    }

}

将产生(所需)输出

Size changed from 0 to 10
Size changed from 10 to 0
Size changed from 0 to 20

这个API有一点遗留的感觉,因为它依赖于将属性名称作为字符串传递,因此不是类型安全的,并且在编译时无法检查。此外,如果任何中间属性为null(例如,如果cel.getShape()在此示例中返回null),则绑定会生成烦人且详细的警告消息(即使这应该是受支持的用例)。

Tomas Mikula在ReactFX library中有一个更现代的实现,请参阅this post以获取说明。使用ReactFX,您可以:

public static void main(String[] args) {
    Cell cell = new Cell();
    Var<Number> size = Val.selectVar(cell.shapeProperty(), Shape::sizeProperty);
    size.addListener(
            (obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));

    cell.getShape().setSize(10);
    cell.setShape(new Shape());
    Shape s = new Shape();
    s.setSize(20);
    cell.setShape(s);
}

最后,如果要创建单元格列表,可以创建ObservableList指定extractor。提取器是将列表中的每个元素(每个Cell)映射到Observable的数组的函数。如果这些Observable中的任何一个发生更改,则列表将触发更新事件。所以你可以做到

ObservableList<Cell> cellList = 
    FXCollections.observableArrayList(cell -> new Observable[] {Bindings.selectInteger(cell.shapeProperty(), "size")});

使用标准API或

ObservableList<Cell> cellList = 
    FXCollections.observableArrayList(cell -> new Observable[] {Val.selectVar(cell.shapeProperty(), Shape::sizeProperty)});

使用ReactFX。然后只需在列表中添加ListChangeListener,如果大小更改(或者形状更改为具有不同大小的新形状),将会通知它。您可以根据需要在返回的数组中添加尽可能多的属性(或属性属性)的可观察对象。

相关问题