JavaFX:使用ObservableMap填充TableView,该ObservableMap具有其值的自定义类

我有以下ObservableMap,我想在TableView显示:

 private ObservableMap 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更改时自动更新。

如果可能的话,让用户可以编辑TableView的第二列和第三列以及在Map中更新这些编辑也是非常好的。

我已经向stackoverflow询问了如何使用ObservableMap填充TableView,以便在此处更新更改: 使用HashMap填充TableView,HashMap将在HashMap更改时更新 。 但是正如你在那里的讨论中所看到的那样,它没有像我这里那样处理自定义类。

这是我到目前为止的解决方案:

  ObservableMap map = FXCollections.observableHashMap(); ObservableList keys = FXCollections.observableArrayList(); map.addListener((MapChangeListener.Change 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 table = new TableView(keys); TableColumn column1 = new TableColumn("Key"); column1.setCellValueFactory(cd -> Bindings.createStringBinding(() -> cd.getValue())); TableColumn column2 = new TableColumn("Value"); column2.setCellValueFactory( ... ); table.getColumns().setAll(column1, column2); 

column2.setCellValueFactory( ... )的地方是倒数第二行column2.setCellValueFactory( ... ) 。 我希望column2显示ShapegetAreaFormula() SimpleStringProperty但我不知道如何设置CellValueFactory来执行此操作。

谢谢你的帮助。

如果您创建一个不可变键值对列表而不是简单的键列表,这是最简单的。 这大大降低了您需要使用的侦听器的复杂性,因为MapChangeListener将始终替换项,如果值已更新且您不需要在cellValueFactoryMap添加侦听器:

键值对类

 public final class MapEntry { 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; } } 

表创建

 ObservableMap map = FXCollections.observableHashMap(); ObservableList> entries = FXCollections.observableArrayList(); map.addListener((MapChangeListener.Change 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 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> table = new TableView<>(entries); TableColumn, String> column1 = new TableColumn<>("Key"); // display item value (= constant) column1.setCellValueFactory(cd -> Bindings.createStringBinding(() -> cd.getValue().getKey())); TableColumn, String> column2 = new TableColumn<>("formula"); column2.setCellValueFactory(cd -> cd.getValue().getValue().areaFormulaProperty()); TableColumn, Number> column3 = new TableColumn<>("sides"); column3.setCellValueFactory(cd -> cd.getValue().getValue().numSidesProperty()); table.getColumns().setAll(column1, column2, column3);