Удаление 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--;