属性属性有意义吗? [英] Do properties of properties make sense?

查看:102
本文介绍了属性属性有意义吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Because this is a question about design I'll start by saying what i have and what i want.

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

I have a design that uses composition. A Cell object holds a Shape and a Background objects (custom made ones for this example). Each of these 2 have their own data that defines them. here is the example in code:

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等类,它们的显示属性绑定到数据属性(我认为这称为模型和视图)。

I also have a GUI that needs to represent many cells and i have written how to do it (how to use color, size etc. to create what i want on the screen). It includes classes such as CellRepresentation, ShapeRepresentation and BackgroundRepresentation that have their display properties bound to the the data properties (i think this is called Model and View).

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

I want to be able to represent changes in the GUI by changing the above data:


  • 用户可以(例如)右键单击形状并设置其颜色。所以上面的数据发生了变化,变化需要反映在GUI中。

  • 用户也可以改变整个形状(例如从另一个单元格中复制粘贴)。甚至整个细胞。这些变化也需要反映在GUI中。

我的问题是哪些班级成员需要是我绑定的JavaFX属性。

My question is which of the class members need to be JavaFX properties that I bind to.

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

Here is what I am thinking: the "leaf" properties (size, color, location...) must be properties so I can bind to them the GUI property. But do I need to make the shape and background objects properties too? Only their properties have "Actual" representation on the screen. Ideally i would have liked it that if Shape changes then all of its properties tell their bindings that they could have changed (maybe the color didn't but size did). But it doesn't work this way - even though the Color of a Shape can change when the Shape changes the Color property won't tell whatever is bound to it that it changed.

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

The same goes for making Cell a property in the lager picture where there are many cells and so on: properties of properties delegating changes.

所以我想创建Shape和Background属性并注册 InvalidationListener 给他们更新他们的属性。这似乎是不对的,因为我认为,在所有对财产的支持下,有一种方法可以做我想要的。

So I thought of making the Shape and Background also properties and registering an InvalidationListener to them updates their properties. This just doesn't seem right because i would think that with all the support for properties there would be a way to do what i want.

有人可以建议一种方法这样做?

Can someone suggest a way to do this?

推荐答案

只使用标准的JavaFX API,你可以利用 Bindings.selectXXX 方法来观察属性的属性。

Using just the standard JavaFX API you can leverage the Bindings.selectXXX methods to observe a "property of a property".

例如:

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),则绑定会生成烦人且详细的警告消息(即使这样应该是一个受支持的用例)。

This API has a bit of a legacy feel to it, in that it relies on passing the property name as a string, and consequently is not typesafe and cannot be checked at compile time. Additionally, if any of the intermediate properties are null (e.g. if cel.getShape() returns null in this example), the bindings generate annoying and verbose warning messages (even though this is supposed to be a supported use case).

Tomas Mikula在他的 ReactFX库中有更现代的实现,请参阅这篇文章用于描述。使用ReactFX,你会这样做:

Tomas Mikula has a more modern implementation in his ReactFX library, see this post for a description. Using ReactFX, you would do:

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 中的任何一个发生更改,则列表将触发更新事件。所以你可以做到

Finally, if you are creating a list of cells, you can create an ObservableList specifying an extractor. The extractor is a function mapping each element in the list (each Cell) to an array of Observables. If any of those Observables changes, the list fires an update event. So you could do

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 添加到列表中,如果大小更改(或者形状更改为具有不同大小的新形状),将通知它。您可以根据需要在返回的数组中添加尽可能多的属性(或属性属性)的可观察对象。

using ReactFX. Then just add a ListChangeListener to the list, and it will be notified if the size changes (or if the shape changes to a new shape with a different size). You can add as many observables that are properties (or properties of properties) of the cell in the returned array as you need.

这篇关于属性属性有意义吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆