如何更新 Table JAVAFX 视图中每一行的值
How to update value of each row in Table View of JAVAFX
我想创建 Table 具有动态列和行的视图,所以我想在从我的数据源中获取值后立即从后台更新每个单元格值,就像我在 swing 中使用的那样setValueAt()
。
所以基本上我不想创建模型 class 因为我的列不固定而且行也不固定而且我不想重新创建 table 视图来更新 table 视图所以请指导我,因为我是 Table javafx 视图的新手。如果您不明白我的问题,请发表评论
谢谢
编辑示例源代码
import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.util.*;
public class DynamicTableView extends Application {
private static final int N_COLS = 5;
private static final int N_ROWS = 1000;
public void start(Stage stage) throws Exception {
TestDataGenerator dataGenerator = new TestDataGenerator();
TableView<ObservableList<String>> tableView = new TableView<>();
// add columns
List<String> columnNames = dataGenerator.getNext(N_COLS);
for (int i = 0; i < columnNames.size(); i++) {
final int finalIdx = i;
TableColumn<ObservableList<String>, String> column = new TableColumn<>(
columnNames.get(i)
);
column.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().get(finalIdx)));
tableView.getColumns().add(column);
}
// add data
for (int i = 0; i < N_ROWS; i++) {
tableView.getItems().add(
FXCollections.observableArrayList(
dataGenerator.getNext(N_COLS)
)
);
}
tableView.setPrefHeight(200);
Scene scene = new Scene(tableView);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
private static class TestDataGenerator {
private static final String[] LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tempus cursus diam ac blandit. Ut ultrices lacus et mattis laoreet. Morbi vehicula tincidunt eros lobortis varius. Nam quis tortor commodo, vehicula ante vitae, sagittis enim. Vivamus mollis placerat leo non pellentesque. Nam blandit, odio quis facilisis posuere, mauris elit tincidunt ante, ut eleifend augue neque dictum diam. Curabitur sed lacus eget dolor laoreet cursus ut cursus elit. Phasellus quis interdum lorem, eget efficitur enim. Curabitur commodo, est ut scelerisque aliquet, urna velit tincidunt massa, tristique varius mi neque et velit. In condimentum quis nisi et ultricies. Nunc posuere felis a velit dictum suscipit ac non nisl. Pellentesque eleifend, purus vel consequat facilisis, sapien lacus rutrum eros, quis finibus lacus magna eget est. Nullam eros nisl, sodales et luctus at, lobortis at sem.".split(" ");
private int curWord = 0;
List<String> getNext(int nWords) {
List<String> words = new ArrayList<>();
for (int i = 0; i < nWords; i++) {
if (curWord == Integer.MAX_VALUE) {
curWord = 0;
}
words.add(LOREM[curWord % LOREM.length]);
curWord++;
}
return words;
}
}
}
正如the javadoc所说,持有table模型的属性是物品。你可以这样做:
table.getItems()
并使用它(添加、删除、清除...)。
正如我在您的示例中看到的那样,您有一个 Table 字符串。为了选择每列显示的内容,您必须使用 setValueFactory()。这样每一列都会知道如何呈现每个值。假设您有字符串:
"Hi how are you?"
而您正在尝试像这样获得 4 列:
hi | how | are | you?
您可以对每一列进行迭代并设置一个 cellValueFactory 来拆分 param.getValue() 并获取其对应的索引。
编辑: 添加了您的 changeValueAt():
public class DynamicTableView extends Application {
private static final int N_COLS = 5;
private static final int N_ROWS = 1000;
public void start(Stage stage) throws Exception {
TestDataGenerator dataGenerator = new TestDataGenerator();
TableView<ObservableList<String>> tableView = new TableView<>();
// add columns
List<String> columnNames = dataGenerator.getNext(N_COLS);
for (int i = 0; i < N_COLS; i++) {
final int index = i;
TableColumn<ObservableList<String>, String> column = new TableColumn<>(columnNames.get(i));
column.setCellValueFactory(cellData -> new ReadOnlyObjectWrapper<>((cellData.getValue().get(index))));
tableView.getColumns().add(column);
}
// add data
for (int i = 0; i < N_ROWS; i++) {
tableView.getItems().add(FXCollections.observableArrayList(dataGenerator.getNext(N_COLS)));
}
tableView.setPrefHeight(200);
Scene scene = new Scene(tableView);
stage.setScene(scene);
stage.show();
changeValueAt(0,0, "thisIsMyNewValue", tableView);
}
private static void changeValueAt(int row, int col, String value, TableView<ObservableList<String>> table){
ObservableList newData = table.getItems().get(row);
newData.set(col, value);
table.getItems().set(row, newData);
}
public static void main(String[] args) {
launch(args);
}
private static class TestDataGenerator {
private static final String[] LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tempus cursus diam ac blandit. Ut ultrices lacus et mattis laoreet. Morbi vehicula tincidunt eros lobortis varius. Nam quis tortor commodo, vehicula ante vitae, sagittis enim. Vivamus mollis placerat leo non pellentesque. Nam blandit, odio quis facilisis posuere, mauris elit tincidunt ante, ut eleifend augue neque dictum diam. Curabitur sed lacus eget dolor laoreet cursus ut cursus elit. Phasellus quis interdum lorem, eget efficitur enim. Curabitur commodo, est ut scelerisque aliquet, urna velit tincidunt massa, tristique varius mi neque et velit. In condimentum quis nisi et ultricies. Nunc posuere felis a velit dictum suscipit ac non nisl. Pellentesque eleifend, purus vel consequat facilisis, sapien lacus rutrum eros, quis finibus lacus magna eget est. Nullam eros nisl, sodales et luctus at, lobortis at sem."
.split(" ");
private int curWord = 0;
List<String> getNext(int nWords) {
List<String> words = new ArrayList<>();
for (int i = 0; i < nWords; i++) {
if (curWord == Integer.MAX_VALUE) {
curWord = 0;
}
words.add(LOREM[curWord % LOREM.length]);
curWord++;
}
return words;
}
}
}
重要的是:
private static void changeValueAt(int row, int col, String value, TableView<ObservableList<String>> table){
ObservableList newData = table.getItems().get(row);
newData.set(col, value);
table.getItems().set(row, newData);
}
每次属性更改时都会触发渲染器。我只是访问要更改的行中的元素,然后访问列中的元素。通过更改它,更改会注意到呈现新值的列。
解释
TableView 中的泛型 class 表示 TableView 持有的 ObservableList 中的泛型 class(在项目 属性).此类型与行的类型一致,因此通过执行:
table.getItems().get(0)
您正在检索保存第一行数据的对象,在您的例子中是一个 ObservableList。这就是为什么你的 table.getItems() returns
ObservableList<ObservableList<String>>
(您提供的通用类型的 ObservableList)。
在呈现每一列时,您必须提供一个 CellValueFactory,指示 TableView 通用类型和列数据类型,然后实现如何从您拥有的信息中获取单元格值。
所有这些都与属性一起工作,这些属性类似于普通数据类型,但会在更改时触发事件。这就是我的方法起作用的原因,一旦您修改了 属性,此 属性 会触发已更改的事件并且 table 会重新呈现(简短说明)。这里的问题是,这种更改不会通过更改列、包含行的列表传播,每个包含列的列表都不会得到通知。这就是为什么我在修改完同一行后再次设置它。
只知道你的例子很少见,因为通常 table 包含普通的 POJO,而你与之交互的唯一 ObservableList 是项目 属性.
我想创建 Table 具有动态列和行的视图,所以我想在从我的数据源中获取值后立即从后台更新每个单元格值,就像我在 swing 中使用的那样setValueAt()
。
所以基本上我不想创建模型 class 因为我的列不固定而且行也不固定而且我不想重新创建 table 视图来更新 table 视图所以请指导我,因为我是 Table javafx 视图的新手。如果您不明白我的问题,请发表评论
谢谢
编辑示例源代码
import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.util.*;
public class DynamicTableView extends Application {
private static final int N_COLS = 5;
private static final int N_ROWS = 1000;
public void start(Stage stage) throws Exception {
TestDataGenerator dataGenerator = new TestDataGenerator();
TableView<ObservableList<String>> tableView = new TableView<>();
// add columns
List<String> columnNames = dataGenerator.getNext(N_COLS);
for (int i = 0; i < columnNames.size(); i++) {
final int finalIdx = i;
TableColumn<ObservableList<String>, String> column = new TableColumn<>(
columnNames.get(i)
);
column.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().get(finalIdx)));
tableView.getColumns().add(column);
}
// add data
for (int i = 0; i < N_ROWS; i++) {
tableView.getItems().add(
FXCollections.observableArrayList(
dataGenerator.getNext(N_COLS)
)
);
}
tableView.setPrefHeight(200);
Scene scene = new Scene(tableView);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
private static class TestDataGenerator {
private static final String[] LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tempus cursus diam ac blandit. Ut ultrices lacus et mattis laoreet. Morbi vehicula tincidunt eros lobortis varius. Nam quis tortor commodo, vehicula ante vitae, sagittis enim. Vivamus mollis placerat leo non pellentesque. Nam blandit, odio quis facilisis posuere, mauris elit tincidunt ante, ut eleifend augue neque dictum diam. Curabitur sed lacus eget dolor laoreet cursus ut cursus elit. Phasellus quis interdum lorem, eget efficitur enim. Curabitur commodo, est ut scelerisque aliquet, urna velit tincidunt massa, tristique varius mi neque et velit. In condimentum quis nisi et ultricies. Nunc posuere felis a velit dictum suscipit ac non nisl. Pellentesque eleifend, purus vel consequat facilisis, sapien lacus rutrum eros, quis finibus lacus magna eget est. Nullam eros nisl, sodales et luctus at, lobortis at sem.".split(" ");
private int curWord = 0;
List<String> getNext(int nWords) {
List<String> words = new ArrayList<>();
for (int i = 0; i < nWords; i++) {
if (curWord == Integer.MAX_VALUE) {
curWord = 0;
}
words.add(LOREM[curWord % LOREM.length]);
curWord++;
}
return words;
}
}
}
正如the javadoc所说,持有table模型的属性是物品。你可以这样做:
table.getItems()
并使用它(添加、删除、清除...)。
正如我在您的示例中看到的那样,您有一个 Table 字符串。为了选择每列显示的内容,您必须使用 setValueFactory()。这样每一列都会知道如何呈现每个值。假设您有字符串:
"Hi how are you?"
而您正在尝试像这样获得 4 列:
hi | how | are | you?
您可以对每一列进行迭代并设置一个 cellValueFactory 来拆分 param.getValue() 并获取其对应的索引。
编辑: 添加了您的 changeValueAt():
public class DynamicTableView extends Application {
private static final int N_COLS = 5;
private static final int N_ROWS = 1000;
public void start(Stage stage) throws Exception {
TestDataGenerator dataGenerator = new TestDataGenerator();
TableView<ObservableList<String>> tableView = new TableView<>();
// add columns
List<String> columnNames = dataGenerator.getNext(N_COLS);
for (int i = 0; i < N_COLS; i++) {
final int index = i;
TableColumn<ObservableList<String>, String> column = new TableColumn<>(columnNames.get(i));
column.setCellValueFactory(cellData -> new ReadOnlyObjectWrapper<>((cellData.getValue().get(index))));
tableView.getColumns().add(column);
}
// add data
for (int i = 0; i < N_ROWS; i++) {
tableView.getItems().add(FXCollections.observableArrayList(dataGenerator.getNext(N_COLS)));
}
tableView.setPrefHeight(200);
Scene scene = new Scene(tableView);
stage.setScene(scene);
stage.show();
changeValueAt(0,0, "thisIsMyNewValue", tableView);
}
private static void changeValueAt(int row, int col, String value, TableView<ObservableList<String>> table){
ObservableList newData = table.getItems().get(row);
newData.set(col, value);
table.getItems().set(row, newData);
}
public static void main(String[] args) {
launch(args);
}
private static class TestDataGenerator {
private static final String[] LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tempus cursus diam ac blandit. Ut ultrices lacus et mattis laoreet. Morbi vehicula tincidunt eros lobortis varius. Nam quis tortor commodo, vehicula ante vitae, sagittis enim. Vivamus mollis placerat leo non pellentesque. Nam blandit, odio quis facilisis posuere, mauris elit tincidunt ante, ut eleifend augue neque dictum diam. Curabitur sed lacus eget dolor laoreet cursus ut cursus elit. Phasellus quis interdum lorem, eget efficitur enim. Curabitur commodo, est ut scelerisque aliquet, urna velit tincidunt massa, tristique varius mi neque et velit. In condimentum quis nisi et ultricies. Nunc posuere felis a velit dictum suscipit ac non nisl. Pellentesque eleifend, purus vel consequat facilisis, sapien lacus rutrum eros, quis finibus lacus magna eget est. Nullam eros nisl, sodales et luctus at, lobortis at sem."
.split(" ");
private int curWord = 0;
List<String> getNext(int nWords) {
List<String> words = new ArrayList<>();
for (int i = 0; i < nWords; i++) {
if (curWord == Integer.MAX_VALUE) {
curWord = 0;
}
words.add(LOREM[curWord % LOREM.length]);
curWord++;
}
return words;
}
}
}
重要的是:
private static void changeValueAt(int row, int col, String value, TableView<ObservableList<String>> table){
ObservableList newData = table.getItems().get(row);
newData.set(col, value);
table.getItems().set(row, newData);
}
每次属性更改时都会触发渲染器。我只是访问要更改的行中的元素,然后访问列中的元素。通过更改它,更改会注意到呈现新值的列。
解释
TableView 中的泛型 class 表示 TableView 持有的 ObservableList 中的泛型 class(在项目 属性).此类型与行的类型一致,因此通过执行:
table.getItems().get(0)
您正在检索保存第一行数据的对象,在您的例子中是一个 ObservableList。这就是为什么你的 table.getItems() returns
ObservableList<ObservableList<String>>
(您提供的通用类型的 ObservableList)。
在呈现每一列时,您必须提供一个 CellValueFactory,指示 TableView 通用类型和列数据类型,然后实现如何从您拥有的信息中获取单元格值。
所有这些都与属性一起工作,这些属性类似于普通数据类型,但会在更改时触发事件。这就是我的方法起作用的原因,一旦您修改了 属性,此 属性 会触发已更改的事件并且 table 会重新呈现(简短说明)。这里的问题是,这种更改不会通过更改列、包含行的列表传播,每个包含列的列表都不会得到通知。这就是为什么我在修改完同一行后再次设置它。
只知道你的例子很少见,因为通常 table 包含普通的 POJO,而你与之交互的唯一 ObservableList 是项目 属性.