使用HashMap填充TableView,HashMap将在HashMap更改时更新 [英] Populating a TableView with a HashMap that will update when HashMap changes
问题描述
我跟着这篇文章
并创建了一个由HashMap中的数据填充的TableView。
TableView
从 HashMap
接收它的数据,称为 map
通过从 map.entrySet()
创建一个 ObservableList
并处理 ObservableList 关闭到
TableView
的构造函数。 (代码如下)
然而,尽管它是 ObservableList
并且 SimpleStringProperty
s,当更改基础HashMap时,TableView不会更新。
public class MapTableView extends Application {
@Override
public void start(Stage stage)throws Exception {
try {
//示例数据
Map< String,String> map = new HashMap<>();
map.put(one,One);
map.put(two,Two);
map.put(three,Three);
//使用Map.Entry的详细类型< String,String>
TableColumn< Map.Entry< String,String>,String> column1 = new TableColumn<>(Key);
column1.setCellValueFactory(new Callback< TableColumn.CellDataFeatures< Map.Entry< String,String>,String>,ObservableValue< String>>(){
@Override
public ObservableValue< String> call(TableColumn.CellDataFeatures< Map.Entry< String,String>,String> p){
//这个回调只返回一个单元格的属性,你不能在这里使用循环
//对于第一列,我们使用键
返回新的SimpleStringProperty(p.getValue()。getKey());
}
});
TableColumn< Map.Entry< String,String>,String> column2 = new TableColumn<>(Value);
column2.setCellValueFactory(new Callback< TableColumn.CellDataFeatures< Map.Entry< String,String>,String>,ObservableValue< String>>(){
@Override
public ObservableValue< String> call(TableColumn.CellDataFeatures< Map.Entry< String,String>,String> p){
//对于第二列,我们使用值
return new SimpleStringProperty(p.getValue() .getValue());
}
});
ObservableList< Map.Entry< String,String>> items = FXCollections.observableArrayList(map.entrySet());
final TableView< Map.Entry< String,String>> table = new TableView<>(items);
table.getColumns()。setAll(column1,column2);
Button changeButton = new Button(Change);
changeButton.setOnAction((ActionEvent e) - > {
map.put(two,2);
System.out.println(map);
});
VBox vBox = new VBox(8);
vBox.getChildren()。addAll(table,changeButton);
场景场景=新场景(vBox,400,400);
stage.setScene(scene);
stage.show();
} catch(Exception e){
e.printStackTrace();
public static void main(String [] args){
launch();
}
}
这正是<除了我添加了下面的按钮之外,还绑定了hashtable和tableview(JavaFX):
按钮changeButton = new Button(Change);
changeButton.setOnAction((ActionEvent e) - > {
map.put(two,2);
System.out.println(map);
});
然后我使用TableView添加到VBox中。
当我点击按钮时, TableView
不会更新。但是,由于 System.out.println(map)
输出的不同,我可以验证底层的 HashMap
是否确实发生了变化。另外,当我点击 TableView
中的列标题以按一列对数据进行排序时,表格数据重新排序后出现新的更新值。
谢谢,
Mark
ObservableMap
用监听器保持 TableView
项和映射关键字相同,并使用 cellValueFactory
和 Bindings.valueAt
,例如: ObservableMap< String,String> ; map = FXCollections.observableHashMap();
ObservableList< String> keys = FXCollections.observableArrayList();
map.addListener((MapChangeListener.Change< ;? extends String,?extends String> change) - > {
boolean removed = change.wasRemoved();
if(删除!= change.wasAdded()){
//不存在现有的键
if(removed){
keys.remove(change.getKey());
} else {
keys.add(change.getKey());
}
}
});
map.put(one,One);
map.put(two,Two);
map.put(three,Three);
最终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(cd - > Bindings.valueAt(map,cd.getValue()));
table.getColumns()。setAll(column1,column2);
I have followed this post
Binding hashmap with tableview (JavaFX)
and created a TableView that is populated by data from a HashMap.
The TableView
receives its data from a HashMap
called map
by creating an ObservableList
from map.entrySet()
and handing that ObservableList
off to the TableView
's constructor. (Code is below)
However, although it's an ObservableList
with SimpleStringProperty
s, the TableView does not update when changes are made to the underlying HashMap.
Here is my code:
public class MapTableView extends Application {
@Override
public void start(Stage stage) throws Exception {
try {
// sample data
Map<String, String> map = new HashMap<>();
map.put("one", "One");
map.put("two", "Two");
map.put("three", "Three");
// use fully detailed type for Map.Entry<String, String>
TableColumn<Map.Entry<String, String>, String> column1 = new TableColumn<>("Key");
column1.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Map.Entry<String, String>, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Map.Entry<String, String>, String> p) {
// this callback returns property for just one cell, you can't use a loop here
// for first column we use key
return new SimpleStringProperty(p.getValue().getKey());
}
});
TableColumn<Map.Entry<String, String>, String> column2 = new TableColumn<>("Value");
column2.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Map.Entry<String, String>, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Map.Entry<String, String>, String> p) {
// for second column we use value
return new SimpleStringProperty(p.getValue().getValue());
}
});
ObservableList<Map.Entry<String, String>> items = FXCollections.observableArrayList(map.entrySet());
final TableView<Map.Entry<String,String>> table = new TableView<>(items);
table.getColumns().setAll(column1, column2);
Button changeButton = new Button("Change");
changeButton.setOnAction((ActionEvent e) -> {
map.put("two", "2");
System.out.println(map);
});
VBox vBox = new VBox(8);
vBox.getChildren().addAll(table, changeButton);
Scene scene = new Scene(vBox, 400, 400);
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch();
}
}
This is exactly the code from Binding hashmap with tableview (JavaFX) except I have added the following button:
Button changeButton = new Button("Change");
changeButton.setOnAction((ActionEvent e) -> {
map.put("two", "2");
System.out.println(map);
});
which I then add to a VBox with the TableView.
When I click the button, the TableView
is not updated. However, I can verify that the underlying HashMap
has indeed changed because of the System.out.println(map)
output. Also when I click on a column header in the TableView
to sort the data by one column, the new updated value appears after the table data is re-sorted.
How can I make the table update automatically when the underlying map is changed?
Thank you,
Mark
Use an ObservableMap
with a listener that keeps the TableView
items and the keys of the map the same and use the cellValueFactory
with Bindings.valueAt
, e.g.:
ObservableMap<String, String> map = FXCollections.observableHashMap();
ObservableList<String> keys = FXCollections.observableArrayList();
map.addListener((MapChangeListener.Change<? extends String, ? extends String> 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("one", "One");
map.put("two", "Two");
map.put("three", "Three");
final TableView<String> table = new TableView<>(keys);
TableColumn<String, String> column1 = new TableColumn<>("Key");
// display item value (= constant)
column1.setCellValueFactory(cd -> Bindings.createStringBinding(() -> cd.getValue()));
TableColumn<String, String> column2 = new TableColumn<>("Value");
column2.setCellValueFactory(cd -> Bindings.valueAt(map, cd.getValue()));
table.getColumns().setAll(column1, column2);
这篇关于使用HashMap填充TableView,HashMap将在HashMap更改时更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!