Javafx:检测对tableView所做的所有更改,包括在任何表行上添加/删除表行和单元格编辑

鉴于我有一个tableView ,如何跟踪所有更改,即添加/删除新行, 其中一个表格单元的值已更改 ,并在检测到任何这些更改时触发相同的事件?

目前,我在下面有以下代码,如果我添加一行,它只会设法检测更改。 当我编辑任何行的表格单元格时以及删除行时 ,它无法检测到更改。

  ObservableList observableListOfTrades =FXCollections.observableArrayList(); observableListOfTrades.add(newTrade); fxTransactionLog.getItems().add(observableListOfTrades.get(observableListOfTrades.size()-1)); observableListOfTrades.addListener(new ListChangeListener() { @Override public void onChanged(ListChangeListener.Change change) { System.out.println("Detected a change! "); } }); 

根据要求,我发布了我的Trade等级

 public class Trade{ // properties private ObjectProperty transactionDate; private StringProperty itemName; private StringProperty buySell; private DoubleProperty volume; private DoubleProperty price; private DoubleBinding transactionFee; public Trade(BuySell buySell, LocalDate transactionDate, double volume, double price){ this.buySell = new SimpleStringProperty(buySell.toString()); this.itemName = new SimpleStringProperty("testing"); this.transactionDate = new SimpleObjectProperty(transactionDate); this.volume = new SimpleDoubleProperty(volume); this.price = new SimpleDoubleProperty(price); } // getters public String getBuySell(){ return this.buySell.get(); } // return Property Object public StringProperty buySellProperty(){ return this.buySell; } // setters public void setBuySell(String buySell){ this.buySell.set(buySell); } public LocalDate getTransactionDate(){ return this.transactionDate.getValue(); } public ObjectProperty transactionDateProperty(){ return this.transactionDate; } public void setTransactionDate(LocalDate transactionDate){ this.transactionDate.set(transactionDate); } public double getVolume(){ return this.volume.get(); } public DoubleProperty volumeProperty(){ return this.volume; } public void setVolume(double volume){ this.volume.set(volume); } public double getPrice(){ return this.price.get(); } public DoubleProperty priceProperty(){ return this.price; } public void setPrice(double price){ this.price.set(price); } public String getItemName(){ return this.itemName.getValue(); } public double getTransactionFee(){ this.transactionFee = this.price.multiply(this.volume).multiply(0.15); return this.transactionFee.getValue(); } public DoubleBinding transactionFeeProperty(){ return this.transactionFee; } public String toString(){ return "Buy: " + getBuySell() + ", Transasction date: " + getTransactionDate() + ", Volume: " + getVolume() + ", Price: " + getPrice() + ", Transaction fee: " + getTransactionFee() ; } } 

你的听众应该回应被删除的项目; 如果不是,则可能是您未显示的代码有问题。

要使ListChangeListener响应属于列表元素的属性的更新,您需要创建指定提取器的列表。

提取器是一个函数,它接受列表的元素,并返回一个可观察值的数组。 然后该列表会观察该数组中的所有值,如果它们发生更改,则会向列表的侦听器触发更新事件。

因此,如果您希望在任何属性发生更改时通知您的侦听器,您可以这样做

 ObservableList observableListOfTrades =FXCollections.observableArrayList(trade -> new Observable[] { trade.transactionDateProperty(), trade.itemNameProperty(), trade.buySellProperty(), trade.volumeProperty(), trade.priceProperty(). trade.transactionFeeProperty() }); 

这是一个完整的例子,使用通常的“联系表”示例:

 import java.util.function.Function; import javafx.application.Application; import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener.Change; import javafx.collections.ObservableList; import javafx.geometry.HPos; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class TableViewWithUpdateListenerExample extends Application { @Override public void start(Stage primaryStage) { // Create an observable list with an extractor. This will ensure // listeners on the list receive notifications if any of the // properties returned by the extractor belonging to a list element // are changed: ObservableList data = FXCollections.observableArrayList(person -> new Observable[] { person.firstNameProperty(), person.lastNameProperty(), person.emailProperty() }); data.addListener((Change c) -> { while (c.next()) { if (c.wasAdded()) { System.out.println("Added:"); c.getAddedSubList().forEach(System.out::println); System.out.println(); } if (c.wasRemoved()) { System.out.println("Removed:"); c.getRemoved().forEach(System.out::println); System.out.println(); } if (c.wasUpdated()) { System.out.println("Updated:"); data.subList(c.getFrom(), c.getTo()).forEach(System.out::println); System.out.println(); } } }); data.addAll( new Person("Jacob", "Smith", "jacob.smith@example.com"), new Person("Isabella", "Johnson", "isabella.johnson@example.com"), new Person("Ethan", "Williams", "ethan.williams@example.com"), new Person("Emma", "Jones", "emma.jones@example.com"), new Person("Michael", "Brown", "michael.brown@example.com") ); TableView tableView = new TableView<>(); tableView.setEditable(true); tableView.setItems(data); tableView.getColumns().add(column("First Name", Person::firstNameProperty)); tableView.getColumns().add(column("Last Name", Person::lastNameProperty)); tableView.getColumns().add(column("Email", Person::emailProperty)); TextField firstNameTF = new TextField(); TextField lastNameTF = new TextField(); TextField emailTF = new TextField(); Button addButton = new Button("Add"); addButton.setOnAction(e -> { Person person = new Person(firstNameTF.getText(), lastNameTF.getText(), emailTF.getText()); firstNameTF.setText(""); lastNameTF.setText(""); emailTF.setText(""); data.add(person); }); GridPane editPane = new GridPane(); editPane.addRow(0, new Label("First Name:"), firstNameTF); editPane.addRow(1, new Label("Last Name:"), lastNameTF); editPane.addRow(2, new Label("Email:"), emailTF); editPane.add(addButton, 0, 3, 2, 1); ColumnConstraints leftCol = new ColumnConstraints(); leftCol.setHalignment(HPos.RIGHT); leftCol.setHgrow(Priority.NEVER); editPane.setHgap(10); editPane.setVgap(5); editPane.getColumnConstraints().addAll(leftCol, new ColumnConstraints()); Button deleteButton = new Button("Delete"); deleteButton.setOnAction(e -> data.remove(tableView.getSelectionModel().getSelectedItem())); deleteButton.disableProperty().bind(Bindings.isEmpty(tableView.getSelectionModel().getSelectedItems())); VBox root = new VBox(10, tableView, editPane, deleteButton); root.setAlignment(Pos.CENTER); primaryStage.setScene(new Scene(root, 800, 600)); primaryStage.show(); } private TableColumn column(String title, Function> property) { TableColumn col = new TableColumn<>(title); col.setCellValueFactory(cellData -> property.apply(cellData.getValue())); col.setCellFactory(TextFieldTableCell.forTableColumn()); return col ; } public static class Person { private final StringProperty firstName = new SimpleStringProperty() ; private final StringProperty lastName = new SimpleStringProperty() ; private final StringProperty email = new SimpleStringProperty() ; public Person(String firstName, String lastName, String email) { setFirstName(firstName); setLastName(lastName); setEmail(email); } public final StringProperty firstNameProperty() { return this.firstName; } public final java.lang.String getFirstName() { return this.firstNameProperty().get(); } public final void setFirstName(final java.lang.String firstName) { this.firstNameProperty().set(firstName); } public final StringProperty lastNameProperty() { return this.lastName; } public final java.lang.String getLastName() { return this.lastNameProperty().get(); } public final void setLastName(final java.lang.String lastName) { this.lastNameProperty().set(lastName); } public final StringProperty emailProperty() { return this.email; } public final java.lang.String getEmail() { return this.emailProperty().get(); } public final void setEmail(final java.lang.String email) { this.emailProperty().set(email); } @Override public String toString() { return getFirstName() + " " + getLastName() + " (" + getEmail() +")"; } } public static void main(String[] args) { launch(args); } }