A relative Java newbie question.
I have a TableView with extractors and a ListChangeListener
added to the underlying ObservableList.
If I have a StringProperty
column in the data model, the change listener doesn't detect changes if I double-click the cell and then hit ENTER without making any changes. That's good.
However, if I define the column as ObjectProperty<String>
and double-click and then hit ENTER, the change listener always detects changes even when none have been made.
Why does that happen? What's the difference between ObjectProperty<String>
and StringProperty
from a change listener's point of view?
I've read Difference between SimpleStringProperty and StringProperty and JavaFX SimpleObjectProperty<T> vs SimpleTProperty and think I understand the differences. But I don't understand why the change listener is giving different results for TProperty
/SimpleTProperty
and ObjectProperty<T>
.
If it helps, here is a MVCE for my somewhat nonsensical case. I'm actually trying to get a change listener working for BigDecimal
and LocalDate
columns and have been stuck on it for 5 days. If I can understand why the change listener is giving different results, I might be able to get my code working.
I'm using JavaFX8 (JDK1.8.0_181), NetBeans 8.2 and Scene Builder 8.3.
package test17;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.Observable;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.converter.DefaultStringConverter;
public class Test17 extends Application {
private Parent createContent() {
ObservableList<TestModel> olTestModel = FXCollections.observableArrayList(testmodel -> new Observable[] {
testmodel.strProperty(),
testmodel.strObjectProperty()
});
olTestModel.add(new TestModel("A", "a"));
olTestModel.add(new TestModel("B", "b"));
olTestModel.addListener((ListChangeListener.Change<? extends TestModel > c) -> {
while (c.next()) {
if (c.wasUpdated()) {
System.out.println("===> wasUpdated() triggered");
}
}
});
TableView<TestModel> table = new TableView<>();
TableColumn<TestModel, String> strCol = new TableColumn<>("strCol");
strCol.setCellValueFactory(cellData -> cellData.getValue().strProperty());
strCol.setCellFactory(TextFieldTableCell.forTableColumn(new DefaultStringConverter()));
strCol.setEditable(true);
strCol.setPrefWidth(100);
strCol.setOnEditCommit((CellEditEvent<TestModel, String> t) -> {
((TestModel) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setStr(t.getNewValue());
});
TableColumn<TestModel, String> strObjectCol = new TableColumn<>("strObjectCol");
strObjectCol.setCellValueFactory(cellData -> cellData.getValue().strObjectProperty());
strObjectCol.setCellFactory(TextFieldTableCell.forTableColumn(new DefaultStringConverter()));
strObjectCol.setEditable(true);
strObjectCol.setPrefWidth(100);
strObjectCol.setOnEditCommit((CellEditEvent<TestModel, String> t) -> {
((TestModel) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setStrObject(t.getNewValue());
});
table.getColumns().addAll(strCol, strObjectCol);
table.setItems(olTestModel);
table.getSelectionModel().setCellSelectionEnabled(true);
table.setEditable(true);
BorderPane content = new BorderPane(table);
return content;
}
public class TestModel {
private StringProperty str;
private ObjectProperty<String> strObject;
public TestModel(
String str,
String strObject
) {
this.str = new SimpleStringProperty(str);
this.strObject = new SimpleObjectProperty(strObject);
}
public String getStr() {
return this.str.get();
}
public void setStr(String str) {
this.str.set(str);
}
public StringProperty strProperty() {
return this.str;
}
public String getStrObject() {
return this.strObject.get();
}
public void setStrObject(String strObject) {
this.strObject.set(strObject);
}
public ObjectProperty<String> strObjectProperty() {
return this.strObject;
}
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle("Test");
stage.setWidth(350);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}