在这种情况下,您应该使用自定义选择模型来防止某些项目被选中。
下面的实现被简化了。它不处理项目列表的更改。此外,它仅实现单选,但希望它显示了一般方法:
public class CustomSelectionModel<T> extends MultipleSelectionModel<T> {
private final ListView<T> listView;
private final ObservableList<Integer> selectedIndices = FXCollections.observableArrayList();
private final ObservableList<Integer> selectedIndicesUnmodifiable = FXCollections.unmodifiableObservableList(selectedIndices);
private final ObservableList<T> selectedItems;
private BiPredicate<Integer, T> leavePredicate;
private BiPredicate<Integer, T> enterPredicate;
public BiPredicate<Integer, T> getLeavePredicate() {
return leavePredicate;
}
public void setLeavePredicate(BiPredicate<Integer, T> leavePredicate) {
this.leavePredicate = leavePredicate;
}
public BiPredicate<Integer, T> getEnterPredicate() {
return enterPredicate;
}
public void setEnterPredicate(BiPredicate<Integer, T> enterPredicate) {
this.enterPredicate = enterPredicate;
}
public CustomSelectionModel(ListView<T> listView) {
if (listView == null) {
throw new IllegalArgumentException();
}
this.listView = listView;
this.selectedItems = new TransformationList<T, Integer>(selectedIndices) {
@Override
protected void sourceChanged(ListChangeListener.Change<? extends Integer> c) {
beginChange();
while (c.next()) {
if (c.wasReplaced()) {
nextReplace(c.getFrom(), c.getTo(), c.getRemoved().stream().map(listView.getItems()::get).collect(Collectors.toList()));
} else if (c.wasRemoved()) {
nextRemove(c.getFrom(), c.getRemoved().stream().map(listView.getItems()::get).collect(Collectors.toList()));
} else if (c.wasAdded()) {
nextAdd(c.getFrom(), c.getTo());
}
}
endChange();
}
@Override
public int getSourceIndex(int index) {
return index;
}
@Override
public T get(int index) {
return listView.getItems().get(getSource().get(index));
}
@Override
public int size() {
return getSource().size();
}
};
}
@Override
public ObservableList<Integer> getSelectedIndices() {
return selectedIndicesUnmodifiable;
}
@Override
public ObservableList<T> getSelectedItems() {
return selectedItems;
}
@Override
public void selectIndices(int index, int... indices) {
clearAndSelect(index); // ignore all indices but the first
}
@Override
public void selectAll() {
selectFirst();
}
@Override
public void selectFirst() {
if (!listView.getItems().isEmpty()) {
clearAndSelect(0);
}
}
@Override
public void selectLast() {
if (!listView.getItems().isEmpty()) {
clearAndSelect(listView.getItems().size() - 1);
}
}
private void moveSelection(int oldIndex, int newIndex) {
if ((leavePredicate == null || leavePredicate.test(oldIndex, oldIndex == -1 ? null : listView.getItems().get(oldIndex)))
&& (enterPredicate == null || enterPredicate.test(newIndex, newIndex == -1 ? null : listView.getItems().get(newIndex)))) {
setSelectedIndex(newIndex);
if (newIndex == -1) {
selectedItems.clear();
setSelectedItem(null);
} else {
setSelectedItem(listView.getItems().get(newIndex));
if (isEmpty()) {
selectedIndices.add(newIndex);
} else {
selectedIndices.set(0, newIndex);
}
}
listView.getFocusModel().focus(newIndex);
}
}
@Override
public void clearAndSelect(int index) {
moveSelection(getSelectedIndex(), index);
}
@Override
public void select(int index) {
clearAndSelect(index);
}
@Override
public void select(T obj) {
int index = listView.getItems().indexOf(obj);
if (index >= 0) {
clearAndSelect(index);
}
}
@Override
public void clearSelection(int index) {
if (getSelectedIndex() == index) {
clearSelection();
}
}
@Override
public void clearSelection() {
moveSelection(getSelectedIndex(), -1);
}
@Override
public boolean isSelected(int index) {
return selectedIndices.contains(index);
}
@Override
public boolean isEmpty() {
return selectedIndices.isEmpty();
}
@Override
public void selectPrevious() {
int index = getSelectedIndex() - 1;
if (index >= 0) {
clearAndSelect(index);
}
}
@Override
public void selectNext() {
int index = getSelectedIndex() + 1;
if (index < listView.getItems().size()) {
clearAndSelect(index);
}
}
}
@Override
public void start(Stage primaryStage) throws Exception {
ListView<Integer> listView = new ListView<>();
for (int i = 0; i < 100; i++) {
listView.getItems().add(i);
}
CustomSelectionModel<Integer> selectionModel = new CustomSelectionModel<>(listView);
listView.setSelectionModel(selectionModel);
CheckBox moveAllowed = new CheckBox("disallow movement");
moveAllowed.selectedProperty().addListener((o, oldValue, newValue) -> selectionModel.setLeavePredicate(newValue ? (index, item) -> false : null));
CheckBox enterOdd = new CheckBox("enter odd items disallowed");
enterOdd.selectedProperty().addListener((o, oldValue, newValue) -> selectionModel.setEnterPredicate(newValue ? (index, item) -> (index & 1) == 0 : null));
Scene scene = new Scene(new ScrollPane(new HBox(listView, new VBox(moveAllowed, enterOdd))));
primaryStage.setScene(scene);
primaryStage.show();
}