如何在双ListView选择系统上实现过滤?

时间:2018-05-09 14:55:47

标签: listview exception javafx

我有两个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 :(得分:0)

首先,你应该使用

lvAvailable.setItems(sortedList);

而不是

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

SortedList(和FilteredList无法修改(因为允许修改会违反他们对其进行排序和/或过滤的合同)。您应该修改基础列表:

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);

    }
}