Как реализовать фильтр в двойной системе выбора ListView? - PullRequest
0 голосов
/ 09 мая 2018

У меня есть два 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);

        }
    }
}

1 Ответ

0 голосов
/ 09 мая 2018

Во-первых, вы должны использовать

lvAvailable.setItems(sortedList);

вместо

lvAvailable.setItems(FXCollections.observableList(sortedList));

A SortedListFilteredList) являются неизменяемыми (поскольку разрешение изменений может привести к нарушению договора о том, что они отсортированы и / или отфильтрованы). Вместо этого вы должны изменить базовые списки:

private void addItem(String item) {

    // If the tag is not already in the Selected list...
    if (item != null && !selectedList.contains(item)) {

        // Add the tag to the Selected list
        selectedList.add(item);

        // Remove it from the available list
        availableList.remove(item);

    }
}

private void removeItem(String item) {

    // If the tag is not already in the Selected list...
    if (item != null && !selectedList.contains(item)) {

        // Add the tag to the Available list
        availableList.add(item);

        // Remove it from the Selected list
        selectedList.remove(item);

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...