在 TableView (JavaFX) 中显示 ArrayList<List<String>> 的值
Showing the values of an ArrayList<List<String>> in a TableView (JavaFX)
我正在尝试从由带字符串值的双嵌套 ArrayList 组成的数据集创建 TableView。不幸的是,我无法在 TableView 中显示所有值。行没有根据数据集编号。
互联网上的大多数解决方案都表明,我应该使用特定的对象实例。但是,我不那样工作。相反,我使用了一个大小不定的字符串矩阵。数据结构如下:
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for(int r=0; r<rows; r++) {
List<String> line = new ArrayList<String>();
for(int c=0; c<cols; c++)
line.add("r: "+r+", c: "+c);
values.add(line);
}
我最好的(但错误的)结果是使用以下代码实现的:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class TestApplication extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
// create values
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for (int r = 0; r < rows; r++) {
List<String> line = new ArrayList<String>();
for (int c = 0; c < cols; c++)
line.add("r: " + r + ", c: " + c);
values.add(line);
}
// show values in table
TableView<List<StringProperty>> tableView = new TableView<List<StringProperty>>();
ObservableList<List<StringProperty>> data = FXCollections.observableArrayList();
for (int c = 0; c < cols; c++) {
TableColumn<List<StringProperty>, String> col = new TableColumn<>("Col: " + c);
tableView.getColumns().add(col);
}
for (int r = 0; r < values.size(); r++) {
List<StringProperty> row = new ArrayList<StringProperty>();
for (int c = 0; c < values.get(r).size(); c++) {
TableColumn<List<StringProperty>, String> col = (TableColumn<List<StringProperty>, String>) tableView.getColumns().get(c);
String val = values.get(r).get(c);
col.setCellValueFactory(cl -> new SimpleStringProperty(new String(val)));
}
data.add(row);
}
tableView.setItems(data);
stage.setScene(new Scene(tableView, 300, 500));
stage.show();
}
}
结果如下:
但是,table 不显示编号的行。我已经尝试了很多东西。但是我没有得到满意的结果。我的错误是什么?
这似乎是这样工作的...我一直在指导
this.
@Override
public void start(Stage stage) throws Exception {
// create values
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for (int r = 0; r < rows; r++) {
List<String> line = new ArrayList<String>();
for (int c = 0; c < cols; c++)
line.add("r: " + r + ", c: " + c);
values.add(line);
}
List<String> colHeads = new ArrayList<String>();
for (int c = 0; c < cols; c++) {
String ch = "Col: " + c;
colHeads.add(ch);
}
// show values in table
List<TableColumn<Map<String, String>, String>> tcs = new ArrayList<TableColumn<Map<String, String>, String>>();
for (int c = 0; c < cols; c++) {
String ch = colHeads.get(c);
TableColumn<Map<String, String>, String> col = new TableColumn<>(ch);
col.setCellValueFactory(new MapValueFactory(ch));
tcs.add(col);
}
TableView<Map<String, String>> tableView = new TableView<>(generateDataInMap(colHeads, values));
tableView.getColumns().setAll(tcs);
stage.setScene(new Scene(tableView, 300, 500));
stage.show();
}
private ObservableList<Map<String, String>> generateDataInMap(List<String> colHeads, List<List<String>> values ) {
ObservableList<Map<String, String>> allData = FXCollections.observableArrayList();
for(int r=0; r<values.size(); r++) {
Map<String, String> dataRow = new HashMap<String, String>();
for(int c=0; c<values.get(r).size(); c++) {
String val = values.get(r).get(c);
dataRow.put(colHeads.get(c), val);
}
allData.add(dataRow);
}
return allData;
}
给定列的 cellValueFactory
是一个函数,它采用包含行数据的包装器(即 List<StringProperty>
)并生成 ObservableValue
(例如 Property
) 其值将显示在该行和列中。
在您的代码中,您每次添加一行时都会更改 cellValueFactory
,因此生成的 cellValueFactory
只是您添加的最后一行中的那个,您只能看到来自最后一行。
您应该只为每列设置一次 cellValueFactory
,它应该是一个将行数据映射到该列的特定值的函数。
例如,以下将为您提供您所需要的:
@Override
public void start(Stage stage) throws Exception {
// create values
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for (int r = 0; r < rows; r++) {
List<String> line = new ArrayList<String>();
for (int c = 0; c < cols; c++)
line.add("r: " + r + ", c: " + c);
values.add(line);
}
// show values in table
TableView<List<StringProperty>> tableView = new TableView<>();
ObservableList<List<StringProperty>> data = FXCollections.observableArrayList();
for (int c = 0; c < cols; c++) {
TableColumn<List<StringProperty>, String> col = new TableColumn<>("Col: " + c);
final int colIndex = c ;
col.setCellValueFactory(cd -> cd.getValue().get(colIndex));
tableView.getColumns().add(col);
}
for (int r = 0; r < values.size(); r++) {
List<StringProperty> row = new ArrayList<StringProperty>();
for (int c = 0; c < values.get(r).size(); c++) {
row.add(new SimpleStringProperty(values.get(r).get(c)));
}
data.add(row);
}
tableView.setItems(data);
stage.setScene(new Scene(tableView, 300, 500));
stage.show();
}
如果数据不会改变,您可能更愿意使用比 StringProperty
更轻的东西,尽管这种小的性能节省的好处值得商榷:
@Override
public void start(Stage stage) throws Exception {
// create values
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for (int r = 0; r < rows; r++) {
List<String> line = new ArrayList<String>();
for (int c = 0; c < cols; c++)
line.add("r: " + r + ", c: " + c);
values.add(line);
}
// show values in table
TableView<List<String>> tableView = new TableView<>();
for (int c = 0; c < cols; c++) {
TableColumn<List<String>, String> col = new TableColumn<>("Col: " + c);
final int colIndex = c ;
col.setCellValueFactory(cd -> new ObservableValue<String>() {
// If data are immutable, there's nothing for a listener to do, so we ignore them:
@Override
public void addListener(InvalidationListener listener) {}
@Override
public void removeListener(InvalidationListener listener) {}
@Override
public void addListener(ChangeListener<? super String> listener) {}
@Override
public void removeListener(ChangeListener<? super String> listener) {}
@Override
public String getValue() {
return cd.getValue().get(colIndex);
}
});
tableView.getColumns().add(col);
}
tableView.setItems(FXCollections.observableList(values));
stage.setScene(new Scene(tableView, 300, 500));
stage.show();
}
我正在尝试从由带字符串值的双嵌套 ArrayList 组成的数据集创建 TableView。不幸的是,我无法在 TableView 中显示所有值。行没有根据数据集编号。
互联网上的大多数解决方案都表明,我应该使用特定的对象实例。但是,我不那样工作。相反,我使用了一个大小不定的字符串矩阵。数据结构如下:
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for(int r=0; r<rows; r++) {
List<String> line = new ArrayList<String>();
for(int c=0; c<cols; c++)
line.add("r: "+r+", c: "+c);
values.add(line);
}
我最好的(但错误的)结果是使用以下代码实现的:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class TestApplication extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
// create values
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for (int r = 0; r < rows; r++) {
List<String> line = new ArrayList<String>();
for (int c = 0; c < cols; c++)
line.add("r: " + r + ", c: " + c);
values.add(line);
}
// show values in table
TableView<List<StringProperty>> tableView = new TableView<List<StringProperty>>();
ObservableList<List<StringProperty>> data = FXCollections.observableArrayList();
for (int c = 0; c < cols; c++) {
TableColumn<List<StringProperty>, String> col = new TableColumn<>("Col: " + c);
tableView.getColumns().add(col);
}
for (int r = 0; r < values.size(); r++) {
List<StringProperty> row = new ArrayList<StringProperty>();
for (int c = 0; c < values.get(r).size(); c++) {
TableColumn<List<StringProperty>, String> col = (TableColumn<List<StringProperty>, String>) tableView.getColumns().get(c);
String val = values.get(r).get(c);
col.setCellValueFactory(cl -> new SimpleStringProperty(new String(val)));
}
data.add(row);
}
tableView.setItems(data);
stage.setScene(new Scene(tableView, 300, 500));
stage.show();
}
}
结果如下:
但是,table 不显示编号的行。我已经尝试了很多东西。但是我没有得到满意的结果。我的错误是什么?
这似乎是这样工作的...我一直在指导 this.
@Override
public void start(Stage stage) throws Exception {
// create values
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for (int r = 0; r < rows; r++) {
List<String> line = new ArrayList<String>();
for (int c = 0; c < cols; c++)
line.add("r: " + r + ", c: " + c);
values.add(line);
}
List<String> colHeads = new ArrayList<String>();
for (int c = 0; c < cols; c++) {
String ch = "Col: " + c;
colHeads.add(ch);
}
// show values in table
List<TableColumn<Map<String, String>, String>> tcs = new ArrayList<TableColumn<Map<String, String>, String>>();
for (int c = 0; c < cols; c++) {
String ch = colHeads.get(c);
TableColumn<Map<String, String>, String> col = new TableColumn<>(ch);
col.setCellValueFactory(new MapValueFactory(ch));
tcs.add(col);
}
TableView<Map<String, String>> tableView = new TableView<>(generateDataInMap(colHeads, values));
tableView.getColumns().setAll(tcs);
stage.setScene(new Scene(tableView, 300, 500));
stage.show();
}
private ObservableList<Map<String, String>> generateDataInMap(List<String> colHeads, List<List<String>> values ) {
ObservableList<Map<String, String>> allData = FXCollections.observableArrayList();
for(int r=0; r<values.size(); r++) {
Map<String, String> dataRow = new HashMap<String, String>();
for(int c=0; c<values.get(r).size(); c++) {
String val = values.get(r).get(c);
dataRow.put(colHeads.get(c), val);
}
allData.add(dataRow);
}
return allData;
}
给定列的 cellValueFactory
是一个函数,它采用包含行数据的包装器(即 List<StringProperty>
)并生成 ObservableValue
(例如 Property
) 其值将显示在该行和列中。
在您的代码中,您每次添加一行时都会更改 cellValueFactory
,因此生成的 cellValueFactory
只是您添加的最后一行中的那个,您只能看到来自最后一行。
您应该只为每列设置一次 cellValueFactory
,它应该是一个将行数据映射到该列的特定值的函数。
例如,以下将为您提供您所需要的:
@Override
public void start(Stage stage) throws Exception {
// create values
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for (int r = 0; r < rows; r++) {
List<String> line = new ArrayList<String>();
for (int c = 0; c < cols; c++)
line.add("r: " + r + ", c: " + c);
values.add(line);
}
// show values in table
TableView<List<StringProperty>> tableView = new TableView<>();
ObservableList<List<StringProperty>> data = FXCollections.observableArrayList();
for (int c = 0; c < cols; c++) {
TableColumn<List<StringProperty>, String> col = new TableColumn<>("Col: " + c);
final int colIndex = c ;
col.setCellValueFactory(cd -> cd.getValue().get(colIndex));
tableView.getColumns().add(col);
}
for (int r = 0; r < values.size(); r++) {
List<StringProperty> row = new ArrayList<StringProperty>();
for (int c = 0; c < values.get(r).size(); c++) {
row.add(new SimpleStringProperty(values.get(r).get(c)));
}
data.add(row);
}
tableView.setItems(data);
stage.setScene(new Scene(tableView, 300, 500));
stage.show();
}
如果数据不会改变,您可能更愿意使用比 StringProperty
更轻的东西,尽管这种小的性能节省的好处值得商榷:
@Override
public void start(Stage stage) throws Exception {
// create values
List<List<String>> values = new ArrayList<List<String>>();
int rows = 10;
int cols = 4;
for (int r = 0; r < rows; r++) {
List<String> line = new ArrayList<String>();
for (int c = 0; c < cols; c++)
line.add("r: " + r + ", c: " + c);
values.add(line);
}
// show values in table
TableView<List<String>> tableView = new TableView<>();
for (int c = 0; c < cols; c++) {
TableColumn<List<String>, String> col = new TableColumn<>("Col: " + c);
final int colIndex = c ;
col.setCellValueFactory(cd -> new ObservableValue<String>() {
// If data are immutable, there's nothing for a listener to do, so we ignore them:
@Override
public void addListener(InvalidationListener listener) {}
@Override
public void removeListener(InvalidationListener listener) {}
@Override
public void addListener(ChangeListener<? super String> listener) {}
@Override
public void removeListener(ChangeListener<? super String> listener) {}
@Override
public String getValue() {
return cd.getValue().get(colIndex);
}
});
tableView.getColumns().add(col);
}
tableView.setItems(FXCollections.observableList(values));
stage.setScene(new Scene(tableView, 300, 500));
stage.show();
}