VBox и HBox
Элементы окна не расставляют по координатам вручную — их кладут в контейнеры (layout panes). Контейнер сам вычисляет, где и какого размера будет каждый узел, и пересчитывает всё при изменении размера окна. Самые простые контейнеры — VBox (столбец) и HBox (строка).
VBox — столбец
VBox ставит узлы друг под другом. Число в конструкторе — расстояние между ними в пикселях:
// src/main/java/com/example/notes/App.java — фрагмент start()
VBox root = new VBox(8);
root.getChildren().addAll(
new Label("Купить молоко"),
new Label("Позвонить Олегу"),
new Label("Прочитать книгу"));
root.setPadding(new Insets(16));В окне появятся три надписи столбиком в левом верхнем углу. getChildren() — список дочерних узлов контейнера, setPadding задаёт внутренний отступ от краёв окна. Insets лежит в пакете javafx.geometry.
HBox — строка
HBox ставит узлы в ряд слева направо. Узлы можно передать прямо в конструктор после расстояния:
// src/main/java/com/example/notes/App.java — фрагмент start()
HBox root = new HBox(8, new Button("Добавить"), new Button("Удалить"));
root.setAlignment(Pos.CENTER_RIGHT);
root.setPadding(new Insets(16));Две кнопки встанут рядом у правого края окна, посередине по высоте. setAlignment выравнивает содержимое: Pos.TOP_LEFT (по умолчанию), Pos.CENTER, Pos.BOTTOM_RIGHT и другие.
Растягивание
По умолчанию узел в HBox получает свой «естественный» размер. Чтобы поле ввода заняло всё свободное место, ему задают приоритет роста:
// src/main/java/com/example/notes/App.java — фрагмент start()
HBox.setHgrow(titleField, Priority.ALWAYS);Для VBox то же делает VBox.setVgrow.
Первый экран записной книжки
Соберём столбец из заголовка, строки с полем и кнопкой и надписи внизу:
// src/main/java/com/example/notes/App.java
package com.example.notes;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class App extends Application {
@Override
public void start(Stage stage) {
Label header = new Label("Мои заметки");
TextField titleField = new TextField();
titleField.setPromptText("Заголовок заметки");
Button addButton = new Button("Добавить");
HBox form = new HBox(8, titleField, addButton);
HBox.setHgrow(titleField, Priority.ALWAYS);
VBox root = new VBox(12, header, form, new Label("Заметок пока нет"));
root.setPadding(new Insets(16));
stage.setTitle("Заметки");
stage.setScene(new Scene(root, 640, 480));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}Запустите mvn javafx:run. Сверху — надпись «Мои заметки», под ней поле ввода и кнопка «Добавить». Поле растянуто на всю ширину и растёт вместе с окном, кнопка остаётся у правого края. Ниже — «Заметок пока нет». При запуске курсор уже стоит в поле, поэтому подсказка «Заголовок заметки» скрыта: серый текст появится, когда фокус уйдёт на кнопку, например по клавише Tab.
Частая ошибка
Один и тот же узел нельзя добавить в контейнер дважды. Код new VBox(label, label) падает с ошибкой java.lang.IllegalArgumentException: Children: duplicate children added: parent = VBox@101b462. Узел может стоять только в одном месте графа сцены: если нужны две одинаковые надписи, создайте два объекта Label.