Удаление JavaFX TreeItem иногда меняет выбор TreeTableView

У меня есть JavaFX TreeTableView. Под его корнем находится множество TreeItem (узлов), и каждый узел может иметь свой собственный дочерний TreeItem (подузлы). Поскольку нет информации для показа ни для каких узлов без подузлов, я хочу удалить их. Но так или иначе, простое действие удаления иногда меняет выбор.

package sample;

import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        TreeItem<String> rootNode = new TreeItem<String>("Root");
        rootNode.setExpanded(true);
        rootNode.getChildren().setAll(new TreeItem<>("Node 0"),
                new TreeItem<>("Node 1"), new TreeItem<>("Node 2"),//);
                new TreeItem<>("Node 3"), new TreeItem<>("Node 4"));
        for (int i = 0; i < 2; i++) {
            TreeItem<String> node = rootNode.getChildren().get(i);
            node.setExpanded(true);
            node.getChildren().setAll(new TreeItem<>("Sub Node " + i + "-0"),
                    new TreeItem<>("Sub Node " + i + "-1"),
                    new TreeItem<>("Sub Node " + i + "-2"));
        }

        TreeTableColumn<String, String> column = new TreeTableColumn<>("Nodes");
        column.setCellValueFactory((TreeTableColumn.CellDataFeatures<String, String> p) -> {
            return new ReadOnlyStringWrapper(p.getValue().getValue());
        });
        column.setPrefWidth(200);

        TreeTableView<String> table = new TreeTableView<>(rootNode);
        table.getColumns().add(column);

        int selectIndex = 4;
        int removeIndex = 3;
        table.getSelectionModel().select(selectIndex);
        System.out.println("Selected index = " + table.getSelectionModel().getSelectedIndex());
        System.out.println("Selected item  = " + table.getSelectionModel().getSelectedItem().getValue());
        table.getRoot().getChildren().remove(removeIndex);
        System.out.println("Selected index = " + table.getSelectionModel().getSelectedIndex());
        System.out.println("Selected item  = " + table.getSelectionModel().getSelectedItem().getValue());

        primaryStage.setTitle("Tree Table View Selection");
        primaryStage.setScene(new Scene(table, 300, 275));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

Код, как он есть, производит следующий вывод:

Selected index = 4
Selected item  = Sub Node 0-2
Selected index = 3
Selected item  = Sub Node 0-1

Однако, если (selectedIndex, removeIndex) изменяется на (3,4), тогда вывод становится:

Selected index = 3
Selected item  = Sub Node 0-1
Selected index = 3
Selected item  = Sub Node 0-1

Без изменений в выбранном индексе.

На самом деле, в моем ограниченном тестовом случае, если selectedIndex меньше или равно removeIndex, то действие удаления не меняет выбор. В противном случае это меняет выбор.

Почему так происходит? Есть ли способ обойти эту проблему?

2 ответа

Решение

Похоже, это ошибка в Java. Я сообщил об этом на bugs.java.com, и теперь он указан в списке как JDK-8193442 и в настоящее время еще не исправлен.

Обходной путь - сохранить selectedItem перед удалением TreeItem и вызвать select после удаления. Однако нужно следить за любым списком изменений в selectedItemProperty.

Здесь происходит то, что у вас есть выбранный индекс, а не выбранный элемент, и когда вы удаляете узлы из дерева, выбранный индекс остается тем же, но элемент с этим индексом теперь другой.

Я думаю, что ваше дерево индексируется в первую очередь по глубине, исходя из того, что вы распечатали, поэтому представьте, что он индексирует карту элементов в виде массива, который выглядит следующим образом: ["Root", "Node 0", "Sub Node 0-0", "Sub Node 0-1", "Sub Node 0-2", "Node 1", "Sub Node 1-1" ... "Sub Node 4-2"],

Когда вы удаляете из этого дерева, вы также удаляете из этого (возможно, воображаемого) массива. Вы удаляете что-то, и все с большим индексом смещается вниз на одну точку.

Чтобы справиться с этим, вам нужно просто сделать проверку, чтобы правильно обновить selectIndex после удаления элемента, чтобы соответствовать его новому индексу. Вы можете сделать что-то вроде следующего:

if(selectIndex > removeIndex)
    selectIndex--;
Другие вопросы по тегам