TableView
ListView показывает одну строку на элемент. Когда у заметки несколько полей, нагляднее таблица TableView: каждый элемент — строка, каждое поле — колонка. Таблица работает с тем же ObservableList, поэтому почти весь код из прошлого урока остаётся: меняем ListView на TableView и описываем колонки.
Таблица вместо списка
// src/main/java/com/example/notes/App.java — поля класса
private final ObservableList<Note> notes = FXCollections.observableArrayList();
private final TableView<Note> table = new TableView<>(notes);Фабрика ячеек ListCell больше не нужна. Везде, где было listView, теперь table: модель выбора у таблицы такая же — table.getSelectionModel().
Колонки
Колонка TableColumn имеет два параметра типа: тип строки (Note) и тип значения в ячейке (String). Конструктор принимает текст заголовка, а фабрика значений говорит, что показать в ячейке:
// src/main/java/com/example/notes/App.java — фрагмент start()
TableColumn<Note, String> titleColumn = new TableColumn<>("Заголовок");
titleColumn.setCellValueFactory(cell -> new SimpleStringProperty(cell.getValue().title()));
TableColumn<Note, String> categoryColumn = new TableColumn<>("Категория");
categoryColumn.setCellValueFactory(cell -> new SimpleStringProperty(cell.getValue().category()));
TableColumn<Note, String> importantColumn = new TableColumn<>("Важная");
importantColumn.setCellValueFactory(
cell -> new SimpleStringProperty(cell.getValue().important() ? "★" : ""));
table.getColumns().add(titleColumn);
table.getColumns().add(categoryColumn);
table.getColumns().add(importantColumn);cell.getValue() — заметка этой строки. Фабрика должна вернуть свойство, поэтому строку оборачивают в SimpleStringProperty.
Ширина и пустая таблица
// src/main/java/com/example/notes/App.java — фрагмент start()
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
table.setPlaceholder(new Label("Заметок пока нет"));| Политика | Что делает |
|---|---|
UNCONSTRAINED_RESIZE_POLICY | По умолчанию: колонки своей ширины, справа может остаться пустое место |
CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN | Колонки заполняют всю ширину, остаток получает последняя |
CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS | Остаток делится между всеми колонками |
setPlaceholder задаёт надпись, которую таблица покажет, когда в ней нет строк.
Размер окна
Таблице нужно больше места, чем списку. Расширим левую панель и окно:
// src/main/java/com/example/notes/App.java — фрагмент start()
VBox listPane = new VBox(8, table, countLabel);
listPane.setPrefWidth(320);
VBox.setVgrow(table, Priority.ALWAYS);
// ...
stage.setScene(new Scene(root, 800, 480));Проверка
Запустите приложение. Слева — таблица с колонками «Заголовок», «Категория» и «Важная»: в первой строке «Купить молоко», «Дом» и звёздочка, во второй «Позвонить Олегу» и «Работа». Справа, как и раньше, форма. Добавьте «Прочитать книгу» с категорией «Идеи» — появится третья строка. Щелчок по заголовку колонки сортирует таблицу по ней, повторный — в обратном порядке, третий — отменяет сортировку.
Частая ошибка
В старых примерах колонку заполняют так: new PropertyValueFactory<>("title"). Этот класс ищет метод getTitle(), а у записи метод называется title(). Колонка остаётся пустой, а в терминале появляется WARNING: Can not retrieve property 'title' in PropertyValueFactory и java.lang.IllegalStateException: Cannot read from unreadable property title. Для записей используйте лямбду, как в этом уроке.