I have a TableView
in SelectionMode.MULTIPLE
. Using a ListChangeListener
I'm able to catch the selection of multiple rows (by pressing Shift).
However my solution only works if the items are being selected in the same column OR in the area without columns. Gif for illustration with 4 examples:
The problem seems to be that the SelectedItems
-list is apparently empty in the last example. I'd really appreciate your help regarding this issue.
Here is my approach:
ObservableList<DataRowModel> dataRows = FXCollections.observableArrayList();
dataRows.addAll(dataSetModel.getRows());
tableDataRow.setItems(dataRows);
tableDataRowStateColumn.setCellValueFactory(f -> f.getValue().getState());
tableDataRow.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
tableDataRow.getSelectionModel().getSelectedItems()
.addListener((ListChangeListener.Change<? extends DataRowModel> c) -> {
while (c.next()) {
c.getRemoved().stream().forEach(remitem -> remitem.setSelected(false));
c.getAddedSubList().stream().forEach(additem -> additem.setSelected(true));
System.out.println(c.getList()); //Empty [] when selected using different columns
}
});
Just for a better understanding of my code: setSelected(...)
sets a BooleanProperty
on my DataRowModel
which is bound to the State-Column.
Without context the reason for using this selected-property seems to be quite silly. However, there are various other fragments of code with ChangeListeners bound to the selected-property.
SSCCE ready to run:
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
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.Group;
import javafx.scene.Scene;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class TableViewSample extends Application {
private TableView<DataRowModel> tableDataRow = new TableView<DataRowModel>();
private TableColumn<DataRowModel, String> tableDataRowNameColumn = new TableColumn<>("Data Item");
private TableColumn<DataRowModel, String> tableDataRowStateColumn = new TableColumn<>("State");
private final ObservableList<DataRowModel> dataRows =
FXCollections.observableArrayList(
new DataRowModel("Concinna", false),
new DataRowModel("Concinna", false),
new DataRowModel("Concinna", false),
new DataRowModel("Concinna", false),
new DataRowModel("Concinna", false)
);
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(500);
stage.setHeight(500);
tableDataRow.setItems(dataRows);
tableDataRowNameColumn.setCellValueFactory(f -> f.getValue().getName());
tableDataRowStateColumn.setCellValueFactory(f -> f.getValue().getState());
tableDataRow.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
tableDataRow.getSelectionModel().getSelectedItems()
.addListener((ListChangeListener.Change<? extends DataRowModel> c) -> {
while (c.next()) {
c.getRemoved().stream().forEach(remitem -> remitem.setSelected(false));
c.getAddedSubList().stream().forEach(additem -> additem.setSelected(true));
}
});
tableDataRow.getColumns().addAll(tableDataRowNameColumn, tableDataRowStateColumn);
((Group) scene.getRoot()).getChildren().addAll(tableDataRow);
stage.setScene(scene);
stage.show();
}
public static class DataRowModel {
private StringProperty name = new SimpleStringProperty(this, "name", "");
private BooleanProperty selected = new SimpleBooleanProperty(this, "selected", true);
private StringProperty state = new SimpleStringProperty(this, "state", "");
public DataRowModel(String name, boolean selected) {
this.name.setValue(name);
this.selected.setValue(selected);
this.selected.addListener((observable, oldVal, newVal) -> {
getState(); // Refresh State value
});
}
public StringProperty getName() {
return name;
}
public BooleanProperty isSelected() {
return selected;
}
public void setSelected(boolean selected) {
if (this.selected.getValue() != selected)
this.selected.setValue(selected);
}
public StringProperty getState() {
String stateStr = "";
if (selected.getValue())
stateStr += "Selected";
state.setValue(stateStr);
return state;
}
}
}
I was able to generate this by editing the Oracle's Person tableview example.
This is a bug, filed as https://bugs.openjdk.java.net/browse/JDK-8096787, and fixed in version 8u60 which is expected to be released in August 2015.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With