使用Map <String,Map <String,String>填充TableView JavaFX
我的大脑已经在燃烧,我找不到在JavaFX中填充TableView的正确方法。 我的数据地图是Map<String, Map<String, String>>
。 第一个键是一个状态名,value是将键作为变量并将值作为变量值的映射。 我需要一张表
| States | x | y | ...
| state 1 | 5 | 6 | ...
等等
编辑:这是我最后的解决方案,填充只有一列和其他填充相同的数据。 这可能是另一个带有价值的foreach。
for (TableColumn<ObservableList<String>, ?> column : table.getColumns()) {
TableColumn<ObservableList<String>, String> col = (TableColumn<ObservableList<String>, String>) column;
col.setCellValueFactory(data -> new ReadOnlyObjectWrapper<>(someValue));
}
我想着这样的解决方案,但它只填充最后一个值的行:
ObservableList<ObservableList<String>> tableData = FXCollections.observableArrayList();
for (Map<String, String> map : map.values()) {
for (Map.Entry<String, String> entry : map.entrySet()) {
if (Utils.getTableColumnByName(table, entry.getKey()) != null) {
TableColumn<ObservableList<String>, String> column = (TableColumn<ObservableList<String>, String>) Utils.getTableColumnByName(table, entry.getKey());
column.setCellValueFactory(data -> new ReadOnlyObjectWrapper<>(entry.getValue()));
}
}
}
for (Integer stateIndex : states) {
tableData.add(FXCollections.observableArrayList("state " + stateIndex));
}
table.setItems(tableData);
我正在寻找任何建议,没有完整的解决方案:)
编辑2:有了这个,我只在开始执行时填充第一行。 我不知道在完成执行后如何填充另一行。 这是在foreach:
TableColumn<ObservableList<String>, String> varColumn = new TableColumn();
varColumn.setText(variable.getText());
varColumn.setCellValueFactory(data -> new ReadOnlyObjectWrapper<>(value.getText()));
table.getColumns().add(varColumn);
而这之后的foreach:
table.setItems(getTableData());
和getTableData():
ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
for (String row : map.keySet()) {
data.add(FXCollections.observableArrayList(row));
}
return data;
我希望这很清楚......谢谢!
TableView的数据结构是一个ObservableList<SomeObject>
,它与您的模型的数据结构不同,它是Map<String, Map<String, String>>
。 因此,您需要一些方法将模型数据结构转换为可在TableView中使用的ObservableList。
我可以想到的几个方法是:
上面的选项2是我在这里提供的示例。 它是一种MVVM(模型,视图,视图模型)架构方法。 该模型是基础的基于地图的结构,视图模型是由TableView视图消耗的可观察列表。
这是一个示例。
import javafx.application.Application;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
public class StateView extends Application {
@Override
public void start(Stage stage) {
ObservableMap<String, ObservableMap<String, String>> states = populateStates();
final TableView<StateItem> tableView = new TableView<>();
tableView.setItems(extractItems(states));
final TableColumn<StateItem, String> stateCol = new TableColumn<>("State");
final TableColumn<StateItem, String> variableCol = new TableColumn<>("Variable");
final TableColumn<StateItem, String> valueCol = new TableColumn<>("Value");
stateCol.setCellValueFactory(new PropertyValueFactory<>("stateName"));
variableCol.setCellValueFactory(new PropertyValueFactory<>("variableName"));
valueCol.setCellValueFactory(new PropertyValueFactory<>("variableValue"));
tableView.getColumns().setAll(stateCol, variableCol, valueCol);
states.addListener((MapChangeListener<String, ObservableMap<String, String>>) change ->
tableView.setItems(extractItems(states))
);
Scene scene = new Scene(tableView);
stage.setScene(scene);
stage.show();
}
private ObservableList<StateItem> extractItems(ObservableMap<String, ObservableMap<String, String>> states) {
return FXCollections.observableArrayList(
states.keySet().stream().sorted().flatMap(state -> {
Map<String, String> variables = states.get(state);
return variables.keySet().stream().sorted().map(
variableName -> {
String variableValue = variables.get(variableName);
return new StateItem(state, variableName, variableValue);
}
);
}).collect(Collectors.toList())
);
}
private static final Random random = new Random(42);
private static final String[] variableNames = { "red", "green", "blue", "yellow" };
private ObservableMap<String, ObservableMap<String, String>> populateStates() {
ObservableMap<String, ObservableMap<String, String>> states = FXCollections.observableHashMap();
for (int i = 0; i < 5; i ++) {
ObservableMap<String, String> variables = FXCollections.observableHashMap();
for (String variableName: variableNames) {
variables.put(variableName, random.nextInt(255) + "");
}
states.put("state " + i, variables);
}
return states;
}
public static void main(String[] args) {
launch(args);
}
public static class StateItem {
private String stateName;
private String variableName;
private String variableValue;
public StateItem(String stateName, String variableName, String variableValue) {
this.stateName = stateName;
this.variableName = variableName;
this.variableValue = variableValue;
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
public String getVariableName() {
return variableName;
}
public void setVariableName(String variableName) {
this.variableName = variableName;
}
public String getVariableValue() {
return variableValue;
}
public void setVariableValue(String variableValue) {
this.variableValue = variableValue;
}
}
}
我所做的是提供一个新的StateItem类,它提供给视图模型的可观察列表,并包含用于表的每一行的stateName,variableName和variableValue值。 有一个单独的提取功能,从模型映射中提取数据并根据需要填充视图模型可观察列表。
什么“根据需要”意味着你将取决于你需要完成什么。 如果您只需要在初始化时预先填充数据,则只需调用一次将数据提取到视图模型即可。
如果您需要视图模型根据底层数据的变化动态更改,那么您需要:
对于示例,我提供了一个基于侦听器的方法的示例。 我将基础模型类从Map<String, Map<String, String>
更改为ObservableMap<String, ObservableMap<String, String>>
,然后使用MapChangeListener
监听最外面的ObservableMap的更改(在您的情况下,它将对应增加一个全新的状态或移除现有状态)。
如果需要保持两个结构之间的附加同步性,例如动态地反映变量被添加或删除,或者变量或状态被重命名或变量值被更新,那么您将需要为最内部的ObservableMap应用附加的侦听器,正在维护您的变量列表。 您可能还会将类型从String更改为StringProperty,以便您可以将模型视图StateItem类中的值绑定到模型中的值,并且还可以将属性访问器添加到StateItem类。
无论如何,上述代码不太可能完全解决您的问题,但可能有助于更好地理解您可能希望评估解决此问题的潜在方法。
另外,也许使用TreeTableView,可能比TableView更适合您的实现。 只取决于你的需求。
多谢你们! 我做的! JavaFX中的表格非常烦人,但我的解决方案适用于任何需要它的人:)
public class Row {
private String state;
private String[] values;
public Row(String state, String... values) {
this.state = state;
this.values = values;
}
public String getState() {
return state;
}
public List<String> getValues() {
return Arrays.asList(values);
}
设置栏:
column.setCellValueFactory(data -> new ReadOnlyObjectWrapper<>(data.getValue().getValues().get(index)));
从地图获取数据:
public ObservableList<Row> getTableData() {
ObservableList<Row> data = FXCollections.observableArrayList();
for (Map.Entry<String, TreeMap<String, String>> entry : map.entrySet()) {
String[] values = new String[entry.getValue().values().size()];
int index = 0;
for (String value : entry.getValue().values()) {
values[index] = value;
index++;
}
Row row = new Row(entry.getKey(), values);
data.add(row);
}
return data;
}
最后:
table.setItems(getTableData());
具有预期输出的表格
当然,它需要一些未定义值的修补程序等等,但它最终会起作用:)
链接地址: http://www.djcxy.com/p/80153.html上一篇: Populate TableView with Map<String, Map<String, String>> JavaFX