У меня есть два ListView
элемента управления, которые я должен иметь возможность перемещать предметы назад и вперед между ними. Перемещение выполняется двойным щелчком по элементу в любом списке.
У меня также есть поле поиска, которое будет фильтровать элементы из списка Available
. Здесь моя проблема.
Я получаю UnsupportedOperationException' when trying to remove an item from the
ListView 's items. My current method of filtering the list seems to convert the
ListView 's list to an
AbstractList`, который нельзя редактировать.
Как разрешить фильтрацию, оставляя базовый список редактируемым?
Основной класс
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Формат FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="vboxMain" alignment="center" spacing="10" xmlns="http://javafx.com/javafx/9.0.1"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<children>
<HBox spacing="10.0">
<children>
<VBox fx:id="vboxAvailableSearchTags" spacing="5.0">
<children>
<Label style="-fx-font-weight: bold;" text="Available"/>
<TextField fx:id="txtSearch" prefWidth="100.0"/>
<ListView fx:id="lvAvailable" prefHeight="200.0" prefWidth="100.0"/>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="5.0">
<children>
<Label style="-fx-font-weight: bold;" text="Seleted"/>
<ListView fx:id="lvSelected" prefHeight="200.0" prefWidth="100.0" VBox.vgrow="ALWAYS"/>
</children>
</VBox>
</children>
<padding>
<Insets top="10.0"/>
</padding>
</HBox>
</children>
</VBox>
Класс контроллера:
public class Controller {
@FXML
private TextField txtSearch;
@FXML
private ListView<String> lvAvailable;
@FXML
private ListView<String> lvSelected;
private ObservableList<String> availableList = FXCollections.observableArrayList();
private ObservableList<String> selectedList = FXCollections.observableArrayList();
@FXML
private void initialize() {
// List of available strings
availableList.addAll(
"One",
"Two",
"Three",
"Four",
"Five"
);
// Initialize the search function
// Wrap the list in a filtered list (initially showing all items)
FilteredList<String> filteredList = new FilteredList<>(availableList.sorted());
// Set the filter predicate whenever the filter changes
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
filteredList.setPredicate(availableItem -> {
// If filter text is empty, show all items
if (newValue == null || newValue.isEmpty()) {
return true;
}
// Compare the tag name and search tags with the filter text
String query = newValue.toLowerCase();
if (availableItem.toLowerCase().contains(query)) {
return true; // Query matches the available item
} else return availableItem.contains(query);
});
});
// Wrap the filtered list in a SortedList
SortedList<String> sortedList = new SortedList<>(filteredList);
lvAvailable.setItems(FXCollections.observableList(sortedList));
lvAvailable.setPlaceholder(new Label("No results"));
// Add the double-click listeners to move selected tags between the two lists
lvAvailable.setOnMouseClicked(mouseEvent -> {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY) &&
mouseEvent.getClickCount() == 2) {
addItem(lvAvailable.getSelectionModel().getSelectedItem());
}
});
lvSelected.setOnMouseClicked(mouseEvent -> {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY) &&
mouseEvent.getClickCount() == 2) {
removeItem(lvSelected.getSelectionModel().getSelectedItem());
}
});
}
private void addItem(String item) {
// If the tag is not already in the Selected list...
if (item != null && !lvSelected.getItems().contains(item)) {
// Add the tag to the Selected list
lvSelected.getItems().add(item);
// Remove it from the available list
lvAvailable.getItems().remove(item);
}
}
private void removeItem(String item) {
// If the tag is not already in the Selected list...
if (item != null && !lvAvailable.getItems().contains(item)) {
// Add the tag to the Available list
lvAvailable.getItems().add(item);
// Remove it from the Selected list
lvSelected.getItems().remove(item);
}
}
}