Деревья
Расмотрим такую математическую структуру как дерево. В JavaFX для работы с деревьями есть компонента TreeView. А дерево представляет собой набор связанных узлов.
Создание дерева
Работается с деревом следующим образом. Добавляем на форму компоненту TreeView
получаем какую-то такую разметку
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.TreeView?>
<?import javafx.scene.layout.*?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
</rowConstraints>
<children>
<VBox>
<children>
<TreeView fx:id="mainTree" prefHeight="368.0" prefWidth="593.0" />
</children>
<padding>
<Insets bottom="4.0" left="4.0" right="4.0" top="4.0" />
</padding>
</VBox>
</children>
</GridPane>
если мы хотим отобразить какую-нибудь структуру, мы делаем следующим образом:
public class Controller implements Initializable {
@FXML
TreeView<Integer> mainTree;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
TreeItem<Integer> root = new TreeItem<>(40);
TreeItem<Integer> child11 = new TreeItem<>(30);
TreeItem<Integer> child12 = new TreeItem<>(50);
// привязываем узлы к корневому узлу
root.getChildren().add(child11);
root.getChildren().add(child12);
// передаем корневой узел в компоненту
mainTree.setRoot(root);
// раскрываем узел
root.setExpanded(true);
}
}
получим такую картинку
мы можем добавлять узлы и к потомкам, по аналогии как было с root, например:
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
TreeItem<Integer> root = new TreeItem<>(40);
TreeItem<Integer> child11 = new TreeItem<>(30);
TreeItem<Integer> child12 = new TreeItem<>(50);
// добавили подузлы к узлам
child11.getChildren().add(new TreeItem<>(33));
child11.getChildren().add(new TreeItem<>(37));
child11.setExpanded(true);
root.getChildren().add(child11);
root.getChildren().add(child12);
mainTree.setRoot(root);
root.setExpanded(true);
}
получится вот так:
Реакция на клик
допустим мы хотим чтобы при выборе узла выводилась информация о нем. В этом случае мы должны добавить обработчик события изменения выбраного значения делается это так
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// ...
root.setExpanded(true);
// добавляем реакцию на клик по узлам
mainTree.getSelectionModel().selectedItemProperty().addListener((changed, oldNode, newNode) -> {
System.out.println(newNode.getValue());
});
}
Доступ к родителю узла
а допустим захотим узнать значение родительского узла, для этого мы можем воспользоваться свойством getParent(), подправим код:
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// ...
root.setExpanded(true);
mainTree.getSelectionModel().selectedItemProperty().addListener((changed, oldNode, newNode) -> {
// получаем доступ к родительскому узлу
TreeItem<Integer> parentNode = newNode.getParent();
// выводим его значение
System.out.println(parentNode.getValue());
});
}
проверяем
Тут у нас кстати ошибка вылетает потому что у корневого узла нет родителя. То есть в идеале писать как-то так:
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// ...
root.setExpanded(true);
mainTree.getSelectionModel().selectedItemProperty().addListener((changed, oldNode, newNode) -> {
// получаем доступ к родительскому узлу
TreeItem<Integer> parentNode = newNode.getParent();
// выводим его значение
if (parentNode != null) {
System.out.println(parentNode.getValue());
}
});
}
Добавление узла в середину дерева
Допустим мы хотим добавить узел куда-нибудь в середину.
Добавим кнопку
в fxml получится вот такая разметка:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.TreeView?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.Button?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
</rowConstraints>
<children>
<VBox>
<children>
<Button onAction="#addNode">Добавить узел</Button>
<TreeView fx:id="mainTree" prefHeight="368.0" prefWidth="593.0" />
</children>
<padding>
<Insets bottom="4.0" left="4.0" right="4.0" top="4.0" />
</padding>
</VBox>
</children>
</GridPane>
теперь добавим реакцию на кнпоку
public class Controller implements Initializable {
@FXML
TreeView<Integer> mainTree;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// ...
}
// НОВЫЙ МЕТОД
public void addNode(ActionEvent actionEvent) {
// берем первого потомка, то бишь 30
TreeItem<Integer> child11 = mainTree.getRoot().getChildren().get(0);
// берем его родителя, то бишь 40
TreeItem<Integer> parent = child11.getParent();
// создаем новый узел со значением 0
TreeItem<Integer> newChild11 = new TreeItem<>(0);
// удаляем у 40 узел 30
parent.getChildren().remove(child11);
// добавляем на место 30 новый узел со значением 0
parent.getChildren().add(0, newChild11);
// подклеиваем 30 к новому узлу
newChild11.getChildren().add(child11);
// раскрываем новый узел
newChild11.setExpanded(true);
}
}
выглядеть это будет вот так:
кстати если понажимать на кнопку по несколько раз, будет все время добавлятся новый узел в одно и тоже место и получится лесенка: