When the row that is currently selected in a TableView is removed, the selection is rendered on another
row but the change listener on the selection model is not triggered. See code below:
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.layout.VBox;
import javafx.scene.layout.VBoxBuilder;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
* When the selected row is removed the selection is rendered on another
* row but there is no notification
*/
public class TableViewSelectionTest extends Application {
static class Order {
String name;
DoubleProperty price = new SimpleDoubleProperty();
DoubleProperty qty = new SimpleDoubleProperty();
Order(String n, double p) {
name = n;
price.set(p);
qty.set(1);
}
@Override
public String toString() {
return name + ": " + qty.get() + " @ " + price.get();
}
}
private static int nextOrderId = 100;
private static Order nextOrder() {
return new Order("Order" + String.valueOf(nextOrderId++), nextOrderId / 10.0);
}
final Order items[] = { new Order("Item 0", 4.0), new Order("Item 1", 5.0),
new Order("Item 2", 6.0), new Order("Item 3", 7.0),
new Order("Item 4", 8.0), new Order("Item 5", 9.0),
new Order("Item 6", 10.0), new Order("Item 7", 11.0) };
@Override
public void start(final Stage primaryStage) throws Exception {
final TableView<Order> tv = new TableView<Order>();
final TextArea ta = new TextArea();
final Button updateButton = new Button("Replace Row");
updateButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(final ActionEvent actionEvent) {
tv.getItems().set(tv.getSelectionModel().getSelectedIndex(), nextOrder());
}
});
final Button deleteButton = new Button("Remove Row");
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(final ActionEvent actionEvent) {
tv.getItems().remove(tv.getSelectionModel().getSelectedIndex());
}
});
final TableColumn<Order, String> nameCol = new TableColumn<Order, String>(
"Item");
final TableColumn<Order, Number> priceCol = new TableColumn<Order, Number>(
"Price");
final TableColumn<Order, Number> qtyCol = new TableColumn<Order, Number>(
"Quantity");
nameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Order, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(
final CellDataFeatures<Order, String> d) {
return new ReadOnlyStringWrapper(d.getValue().name);
}
});
priceCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Order, Number>, ObservableValue<Number>>() {
@Override
public ObservableValue<Number> call(
final CellDataFeatures<Order, Number> cellData) {
return cellData.getValue().price;
};
});
qtyCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Order, Number>, ObservableValue<Number>>() {
@Override
public ObservableValue<Number> call(
final CellDataFeatures<Order, Number> cellData) {
return cellData.getValue().qty;
};
});
tv.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Order>() {
@Override
public void changed(ObservableValue<? extends Order> arg0,
Order arg1, Order newOrder) {
ta.setText(String.format("Selected Order %s", newOrder));
}
});
tv.getColumns().addAll(nameCol, priceCol, qtyCol);
tv.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tv.getItems().addAll(items);
final HBox hb = HBoxBuilder.create().children(updateButton, deleteButton)
.build();
final VBox vb = VBoxBuilder.create().children(tv, ta, hb).build();
primaryStage.setScene(new Scene(vb));
primaryStage.setHeight(500.0);
primaryStage.show();
}
public static void main(final String args[]) {
launch(args);
}
}
row but the change listener on the selection model is not triggered. See code below:
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.layout.VBox;
import javafx.scene.layout.VBoxBuilder;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
* When the selected row is removed the selection is rendered on another
* row but there is no notification
*/
public class TableViewSelectionTest extends Application {
static class Order {
String name;
DoubleProperty price = new SimpleDoubleProperty();
DoubleProperty qty = new SimpleDoubleProperty();
Order(String n, double p) {
name = n;
price.set(p);
qty.set(1);
}
@Override
public String toString() {
return name + ": " + qty.get() + " @ " + price.get();
}
}
private static int nextOrderId = 100;
private static Order nextOrder() {
return new Order("Order" + String.valueOf(nextOrderId++), nextOrderId / 10.0);
}
final Order items[] = { new Order("Item 0", 4.0), new Order("Item 1", 5.0),
new Order("Item 2", 6.0), new Order("Item 3", 7.0),
new Order("Item 4", 8.0), new Order("Item 5", 9.0),
new Order("Item 6", 10.0), new Order("Item 7", 11.0) };
@Override
public void start(final Stage primaryStage) throws Exception {
final TableView<Order> tv = new TableView<Order>();
final TextArea ta = new TextArea();
final Button updateButton = new Button("Replace Row");
updateButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(final ActionEvent actionEvent) {
tv.getItems().set(tv.getSelectionModel().getSelectedIndex(), nextOrder());
}
});
final Button deleteButton = new Button("Remove Row");
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(final ActionEvent actionEvent) {
tv.getItems().remove(tv.getSelectionModel().getSelectedIndex());
}
});
final TableColumn<Order, String> nameCol = new TableColumn<Order, String>(
"Item");
final TableColumn<Order, Number> priceCol = new TableColumn<Order, Number>(
"Price");
final TableColumn<Order, Number> qtyCol = new TableColumn<Order, Number>(
"Quantity");
nameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Order, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(
final CellDataFeatures<Order, String> d) {
return new ReadOnlyStringWrapper(d.getValue().name);
}
});
priceCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Order, Number>, ObservableValue<Number>>() {
@Override
public ObservableValue<Number> call(
final CellDataFeatures<Order, Number> cellData) {
return cellData.getValue().price;
};
});
qtyCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Order, Number>, ObservableValue<Number>>() {
@Override
public ObservableValue<Number> call(
final CellDataFeatures<Order, Number> cellData) {
return cellData.getValue().qty;
};
});
tv.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Order>() {
@Override
public void changed(ObservableValue<? extends Order> arg0,
Order arg1, Order newOrder) {
ta.setText(String.format("Selected Order %s", newOrder));
}
});
tv.getColumns().addAll(nameCol, priceCol, qtyCol);
tv.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tv.getItems().addAll(items);
final HBox hb = HBoxBuilder.create().children(updateButton, deleteButton)
.build();
final VBox vb = VBoxBuilder.create().children(tv, ta, hb).build();
primaryStage.setScene(new Scene(vb));
primaryStage.setHeight(500.0);
primaryStage.show();
}
public static void main(final String args[]) {
launch(args);
}
}