Lists, Tables & ComboBoxes
Lists, Tables & ComboBoxes
Three controls dominate data-presentation in almost every real JavaFX application: ListView, TableView, and ComboBox. Each follows the same architectural philosophy — a Model-View separation where the control renders whatever data you put into an ObservableList, and updates itself automatically when that list changes. Understanding this pattern once means you understand all three controls.
The ObservableList Foundation
Before touching any control, internalize this: JavaFX data controls do not hold copies of your data. They hold a reference to an ObservableList<T> and watch it for changes. Add an item to the list, the control repaints. Remove one, the row disappears. You never call a "refresh" method.
ListView
ListView<T> renders a scrollable list of items, one per row. The generic type can be anything — String, a model class, an enum.
getSelectionModel() returns a MultipleSelectionModel that exposes both selectedItemProperty() (single binding) and getSelectedItems() (observable collection for multi-select). Always read selection through this API — never traverse the cell tree yourself.
Custom Cell Rendering with Cell Factories
By default, ListView calls toString() on each item. For richer rows — icons, buttons, formatted text — supply a cell factory: a Callback that the list calls once per visible cell to create a ListCell<T>. JavaFX then recycles those cells as the user scrolls (the same principle as RecyclerView on Android).
super.updateItem() first and always handle the empty case. Skipping either step causes phantom content to appear in blank rows — a very common JavaFX beginner bug. Cells are reused; if you do not clear them when empty == true, the old data bleeds into empty slots.
TableView
TableView<T> presents a collection of objects in a grid of columns. Each TableColumn<T, CellValue> knows how to extract one field from an object of type T.
PropertyValueFactory uses reflection to call the getter whose name matches the string you pass. The cleaner, refactoring-safe alternative is a lambda cell-value factory that reads the JavaFX property directly:
Editable Cells
Making a table cell editable requires two steps: tell the table it is editable, then give the column an editable cell factory and a setOnEditCommit handler that writes the new value back to the model.
TableView and ListView bind most efficiently to Property objects (SimpleStringProperty, SimpleIntegerProperty, etc.). If a property changes programmatically, the table cell updates automatically — no manual refresh calls needed.
ComboBox
ComboBox<T> combines a button that shows the current selection with a drop-down list. It also supports an optional editable text field when setEditable(true) is called.
ComboBox with Custom Objects
When the generic type is not a String, supply a StringConverter so the control knows how to display items in both the button face and the drop-down list.
Comparing the Three Controls
- ListView: Single-column list of items. Use for navigation panels, option lists, or any scrollable collection where one piece of data per row is enough.
- TableView: Multi-column grid. Use when each item has several fields you need to show side-by-side, with optional sorting and editing.
- ComboBox: Compact selection control. Use inside forms where space is limited and the user picks one value from a bounded set.
Summary
All three controls share the ObservableList data model — change the list, the UI updates automatically. ListView and TableView use cell factories for custom rendering and follow a cell-recycling scheme that handles thousands of rows efficiently. TableView ties columns to model properties either through PropertyValueFactory or lambda factories, and supports in-place editing via setOnEditCommit. ComboBox integrates cleanly into forms and gains display customization through a StringConverter. In the next lesson you will arrange these controls on screen using HBox and VBox layout panes.