JavaFX:使用ObservableMap填充TableView,该ObservableMap具有其值的自定义类 [英] JavaFX: Populate TableView with an ObservableMap that has a custom class for its values

查看:137
本文介绍了JavaFX:使用ObservableMap填充TableView,该ObservableMap具有其值的自定义类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下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 cellValueFactorys:

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屋!

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