JavaFX:使用ObservableMap填充TableView,该ObservableMap具有其值的自定义类 [英] JavaFX: Populate TableView with an ObservableMap that has a custom class for its values
问题描述
我有以下ObservableMap,我想在 TableView
中显示:
I have the following ObservableMap that I would like to display in a TableView
:
private ObservableMap<String, Shape> myShapes = FXCollections.observableHashMap();
其中 Shape
定义如下:
public class Shape {
private StringProperty areaFormula = new SimpleStringProperty();
private IntegerProperty numSides = new SimpleIntegerProperty();
public Shape(String areaFormula, int numSides)
{
this.areaFormula.set(areaFormula);
this.numSides.set(numSides);
}
public String getAreaFormula() { return areaFormula.get(); }
public void setAreaFormula(String areaFormula) { this.areaFormula.set(areaFormula); }
public StringProperty areaFormulaProperty() { return this.areaFormula; }
public int getNumSides() { return numSides.get(); }
public void setNumSides(int sides) { this.numSides.set(sides); }
public IntegerProperty numSidesProperty() { return this.numSides; }
}
我希望TableView的第一列是Map Key(称之为 key
),第二列为 myShapes.get(key).getAreaFormula()
,第三列列为 myShapes.get(key).getnumSides()
。我希望TableView在Map更改时自动更新。
I would like the first column of the TableView to be the Map Key (call it key
), the second column to be myShapes.get(key).getAreaFormula()
, and the third column to be myShapes.get(key).getnumSides()
. And I would like the TableView to automatically update when the Map is changed.
制作 TableView
可由用户编辑,并在地图中更新这些编辑。
It would also be really nice to make the second and third columns of the TableView
editable by the user, if possible, with those edits being updated in the Map.
我已经询问了有关填充TableView的stackoverflow使用ObservableMap,它将更新此处的更改:
使用HashMap填充TableView,HashMap将在HashMap更改时更新。但是正如你在那里的讨论中所看到的那样,它没有像我这里那样处理自定义类。
I have already asked stackoverflow about populating a TableView with an ObservableMap such that it will update on changes here: Populating a TableView with a HashMap that will update when HashMap changes . However as you can see in the discussion there, it does not handle a custom class like I have here.
到目前为止,这是我的解决方案:
Here is my solution so far:
ObservableMap<String, Shape> map = FXCollections.observableHashMap();
ObservableList<String> keys = FXCollections.observableArrayList();
map.addListener((MapChangeListener.Change<? extends String, ? extends Shape> change) -> {
boolean removed = change.wasRemoved();
if (removed != change.wasAdded()) {
// no put for existing key
if (removed) {
keys.remove(change.getKey());
} else {
keys.add(change.getKey());
}
}
});
map.put("square", new Shape("L^2", 4));
map.put("rectangle", new Shape("LW", 4));
map.put("triangle", new Shape("0.5HB", 3));
final TableView<String> table = new TableView<>(keys);
TableColumn<String, String> column1 = new TableColumn<>("Key");
column1.setCellValueFactory(cd -> Bindings.createStringBinding(() -> cd.getValue()));
TableColumn<String, String> column2 = new TableColumn<>("Value");
column2.setCellValueFactory( ... );
table.getColumns().setAll(column1, column2);
我遇到的地方是倒数第二行 column2.setCellValueFactory(...)
。我希望 column2
显示 Shape
的 getAreaFormula()
SimpleStringProperty
但我不知道如何设置 CellValueFactory
这样做。
The place where I'm stuck is the second-to-last line column2.setCellValueFactory( ... )
. I would like column2
to display the Shape
's getAreaFormula()
SimpleStringProperty
but I don't know how to set up the CellValueFactory
to do so.
感谢您的帮助。
推荐答案
如果您创建一个不可变的列表,这是最简单的键值对而不是简单的键列表。这大大降低了您需要使用的侦听器的复杂性,因为 MapChangeListener
将始终替换项目,如果值已更新且您不需要添加侦听器 cellValueFactory
中的地图
:
It's easiest, if you create a list of immutable key-value pairs instead of simply a list of keys. This drastically reduces the complexity of the listeners you need to use, since the MapChangeListener
will always replace an item, if a value is updated and you don't need to add listeners to the Map
in the cellValueFactory
s:
public final class MapEntry<K, V> {
private final K key;
private final V value;
public MapEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public boolean equals(Object obj) {
// check equality only based on keys
if (obj instanceof MapEntry) {
MapEntry<?, ?> other = (MapEntry<?, ?>) obj;
return Objects.equals(key, other.key);
} else {
return false;
}
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
创建表格
Table creation
ObservableMap<String, Shape> map = FXCollections.observableHashMap();
ObservableList<MapEntry<String, Shape>> entries = FXCollections.observableArrayList();
map.addListener((MapChangeListener.Change<? extends String, ? extends Shape> change) -> {
boolean removed = change.wasRemoved();
if (removed != change.wasAdded()) {
if (removed) {
// no put for existing key
// remove pair completely
entries.remove(new MapEntry<>(change.getKey(), (Shape) null));
} else {
// add new entry
entries.add(new MapEntry<>(change.getKey(), change.getValueAdded()));
}
} else {
// replace existing entry
MapEntry<String, Shape> entry = new MapEntry<>(change.getKey(), change.getValueAdded());
int index = entries.indexOf(entry);
entries.set(index, entry);
}
});
map.put("one", new Shape("a", 1));
map.put("two", new Shape("b", 2));
map.put("three", new Shape("c", 3));
final TableView<MapEntry<String, Shape>> table = new TableView<>(entries);
TableColumn<MapEntry<String, Shape>, String> column1 = new TableColumn<>("Key");
// display item value (= constant)
column1.setCellValueFactory(cd -> Bindings.createStringBinding(() -> cd.getValue().getKey()));
TableColumn<MapEntry<String, Shape>, String> column2 = new TableColumn<>("formula");
column2.setCellValueFactory(cd -> cd.getValue().getValue().areaFormulaProperty());
TableColumn<MapEntry<String, Shape>, Number> column3 = new TableColumn<>("sides");
column3.setCellValueFactory(cd -> cd.getValue().getValue().numSidesProperty());
table.getColumns().setAll(column1, column2, column3);
这篇关于JavaFX:使用ObservableMap填充TableView,该ObservableMap具有其值的自定义类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!