Reputation: 148
I want to replace the old data with newly input edited data in tableView.The column2 works, yet column1 does not. I found out that entrySet() key changes, yet the key in tableView does not change!I am observing the entrySet of hashmap, therefore I would expect the table to update automatically when an entry is removed or added. Is this assumption wrong?
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.IntegerStringConverter;
import java.util.Map;
public class EnumerateTable {
private ObservableList<Map.Entry<Integer, String>> items;
private TableView<Map.Entry<Integer,String>> table;
public EnumerateTable( Enumerator x) {
TableColumn<Map.Entry<Integer, String>, Integer> column1 = new TableColumn<>("Key");
column1.setCellValueFactory(p ->new SimpleIntegerProperty(p.getValue().getKey()).asObject());
TableColumn<Map.Entry<Integer, String>, String> column2 = new TableColumn<>("Value");
column2.setCellValueFactory(p -> new SimpleStringProperty(p.getValue().getValue()));
items = FXCollections.observableArrayList(x.enums.entrySet());
table = new TableView<>(items);
table.setEditable(true);
column1.setEditable(true);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.getColumns().setAll(column1, column2);
column1.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
column1.setOnEditCommit(
t -> {
String value = t.getTableView().getItems().get(
t.getTablePosition().getRow()).getValue();
int key = t.getTableView().getItems().get(
t.getTablePosition().getRow()).getKey();
System.out.println(key+" key");
System.out.println(x.enums.entrySet()+" before");
x.getEnums().remove(key);
x.getEnums().put(t.getNewValue(),value);
System.out.println(t.getNewValue()+" new value");
System.out.println(x.getEnums().entrySet()+" after");
table.refresh();
});
column2.setCellFactory(TextFieldTableCell.forTableColumn());
column2.setOnEditCommit(
t -> {
int key= t.getTableView().getItems().get(t.getTablePosition().getRow()).getKey();
System.out.println(x.getEnums().size());
x.getEnums().put(key,t.getNewValue());
System.out.println(x.getEnums().size());
});
}
public TableView<Map.Entry<Integer, String>> getTable() {
return table;
}
}
The getEnums() method comes from
import java.util.HashMap;
public class Enumerator {
String name;
HashMap<Integer,String> enums;
public Enumerator(String name)
{ this.name = name;
enums = new HashMap<>();}
public HashMap<Integer, String> getEnums() {
return enums;
}
}
Upvotes: 0
Views: 881
Reputation: 82451
I am observing the entrySet of hashmap
No you're not observing anything. In fact HashMap
does not provide any functionality allowing you to observe changes.
FXCollections.observableArrayList(x.enums.entrySet());
Simply creates a new ObservableList
and copies the contents from the Collection
passed as parameter to this list. After adding or removing keys from the map, the entries are no longer guaranteed to work, but there's no notification of updates and the ObservableList
is not updated, if the keys in the map change.
I recommend using the keys as TableView
's items instead and update the map and the item list on a onEditCommit
event for the first column.
@Override
public void start(Stage primaryStage) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "foo");
map.put(23, "bar");
ObservableList<Integer> keys = FXCollections.observableArrayList(map.keySet());
TableView<Integer> table = new TableView<>(keys);
TableColumn<Integer, Integer> column1 = new TableColumn<>("Key");
column1.setCellValueFactory(p -> new SimpleObjectProperty<>(p.getValue()));
TableColumn<Integer, String> column2 = new TableColumn<>("Value");
column2.setCellValueFactory(p -> new SimpleStringProperty(map.get(p.getValue())));
table.setEditable(true);
column1.setEditable(true);
table.getColumns().setAll(column1, column2);
column1.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
column1.setOnEditCommit(t -> {
Integer key = t.getRowValue();
Integer newKey = t.getNewValue();
if (!key.equals(newKey)) {
if (map.containsKey(newKey)) {
// make sure this cell's value remains unmodified
table.refresh();
} else {
int rowIndex = t.getTablePosition().getRow();
map.put(newKey, map.remove(key));
keys.set(rowIndex, newKey);
}
}
});
column2.setCellFactory(TextFieldTableCell.forTableColumn());
column2.setOnEditCommit(t -> {
Integer key = t.getRowValue();
map.put(key, t.getNewValue());
});
Scene scene = new Scene(table);
primaryStage.setScene(scene);
primaryStage.show();
}
Note that the code above only works as long as you don't modify the map data in some other way. If you modify the map some other way, you need to be sure to keep the keys
list up to date and make sure to call table.refresh()
, if you modify a value.
(In this case it may be best to use a ObservableMap
instead of a HashMap
which allows you to add a listener that keeps the list updated.)
Upvotes: 1