Имеют ли свойства свойства смысл?
Потому что это вопрос дизайна, я начну с того, что имею и чего хочу.
У меня есть дизайн, который использует композицию. Cell
объект содержит Shape
и Background
объекты (изготовленные на заказ для этого примера). Каждый из этих 2 имеет свои собственные данные, которые их определяют. Вот пример в коде:
class Cell {
Shape shape;
Background background;
class Shape {
int size;
Color color;
Point location;
//...
}
class Background {
Color color;
String name;
CoverType type;
//...
}
}
У меня также есть графический интерфейс, который должен представлять много ячеек, и я написал, как это сделать (как использовать цвет, размер и т. Д., Чтобы создать то, что я хочу на экране). Он включает в себя такие классы, как CellRepresentation, ShapeRepresentation и BackgroundRepresentation, свойства отображения которых связаны со свойствами данных (я думаю, это называется Model and View).
Я хочу иметь возможность представлять изменения в графическом интерфейсе путем изменения вышеуказанных данных:
- пользователь может (например) щелкнуть правой кнопкой мыши форму и установить ее цвет. Таким образом, данные выше изменяются, и изменение должно быть отражено в графическом интерфейсе.
- пользователь также может изменить всю форму (например, скопировать ее из другой ячейки). Или даже целая клетка. Эти изменения также необходимо отразить в графическом интерфейсе.
Мой вопрос заключается в том, с какими членами класса должны быть свойства JavaFX, с которыми я связываюсь.
Вот что я думаю: "листовые" свойства (размер, цвет, местоположение...) должны быть свойствами, чтобы я мог связать их со свойством GUI. Но нужно ли мне также настроить свойства объектов формы и фона? Только их свойства имеют "Актуальное" представление на экране. В идеале мне бы понравилось, что если Shape изменится, то все его свойства сообщают своим привязкам, что они могли измениться (возможно, цвет не изменился, но размер изменился). Но это не работает таким образом - даже если цвет фигуры может измениться, когда фигура изменится, свойство Color не сообщит всему, что с ним связано, что оно изменилось.
То же самое относится и к тому, чтобы сделать ячейку свойством в лагере, где много ячеек и т. Д.: Свойства, делегирующие изменения.
Поэтому я подумал о том, чтобы сделать Shape и Background также свойствами и зарегистрировать InvalidationListener
им обновляет свои свойства. Это просто не кажется правильным, потому что я думал бы, что со всей поддержкой свойств был бы способ сделать то, что я хочу.
Может кто-нибудь предложить способ сделать это?
1 ответ
Используя только стандартный 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 выглядит немного устаревшим, так как он основан на передаче имени свойства в виде строки и, следовательно, не является безопасным для типов и не может быть проверен во время компиляции. Кроме того, если какое-либо из промежуточных свойств является нулевым (например, если cel.getShape()
в этом примере возвращает null), привязки генерируют раздражающие и подробные предупреждающие сообщения (даже если предполагается, что это поддерживаемый вариант использования).
Томас Микула имеет более современную реализацию в своей библиотеке ReactFX, см. Этот пост для описания. Используя 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
s. Если какой-либо из этих 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
в список, и он будет уведомлен, если размер меняется (или если форма меняется на новую форму с другим размером). Вы можете добавить столько наблюдаемых, которые являются свойствами (или свойствами свойств) ячейки в возвращаемом массиве, сколько вам нужно.