How to move items between two ListViews with change listener JavaFX

走远了吗. 提交于 2020-01-03 10:55:52

问题


I have two ListViews, allStudentsList has items already populated within it, currentStudentList has none. My aim for when the user selects an item in allStudentList is for that item be moved into currentStudentList. I have done this by placing a listener on the selection model of the allStudentList.

I get an IndexOutOfBoundsException and I am not sure why this is occurring. From testing, it seems that this problem is isolated to the last 4 lines of this method yet I am not sure why.

allStudentsList.getSelectionModel().selectedItemProperty()
        .addListener((observableValue, oldValue, newValue) -> {
            if (allStudentsList.getSelectionModel().getSelectedItem() != null) {

                ArrayList<String> tempCurrent = new ArrayList<>();
                for (String s : currentStudentList.getItems()) {
                    tempCurrent.add(s);
                }

                ArrayList<String> tempAll = new ArrayList<>();
                for (String s : allStudentsList.getItems()) {
                    tempAll.add(s);
                }

                tempAll.remove(newValue);
                tempCurrent.add(newValue);

                // clears current studentlist and adds the new list
                if (currentStudentList.getItems().size() != 0) {
                    currentStudentList.getItems().clear();
                }
                currentStudentList.getItems().addAll(tempCurrent);

                // clears the allStudentList and adds the new list
                if (allStudentsList.getItems().size() != 0) {
                    allStudentsList.getItems().clear();
                }
                allStudentsList.getItems().addAll(tempAll);
            }
        });

回答1:


As a quick fix you can wrap the code parts that modify the item lists into a Platform.runLater(...) block:

Platform.runLater(() -> {
    // clears current studentlist and adds the new list
    if (currentStudentList.getItems().size() != 0) 
        currentStudentList.getItems().clear();

    currentStudentList.getItems().addAll(tempCurrent);
});

Platform.runLater(() -> {
    // clears the allStudentList and adds the new list
    if (allStudentsList.getItems().size() != 0) 
        allStudentsList.getItems().clear();

    allStudentsList.getItems().addAll(tempAll);
});

The problem is that you cannot change the selection while a selection change is being processed. As you remove all elements with allStudentsList.getItems().clear();, the selection will change (the selected index will be -1), the mentioned condition will met. This is what the usage of the Platform.runLater(...) block will prevent by "postponing" the modification.

But your whole handler could be exchanged with

allStudentsList.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue) -> {
    if (newValue != null) {

        Platform.runLater(() -> {
            allStudentsList.getSelectionModel().select(-1);
            currentStudentList.getItems().add(newValue);
            allStudentsList.getItems().remove(newValue);
        });
    }
});

It sets the selected index to -1: nothing is selected in the ListView to avoid changing to a different item when removing the current one (this was done implicitly in your version by clearing the list), then it adds the currently selected element to the s"elected list", then it removes the current element from the "all item list". All of these actions are wrapped in the mentioned Platform.runLater(...) block.



来源:https://stackoverflow.com/questions/39714874/how-to-move-items-between-two-listviews-with-change-listener-javafx

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!