JavaFX TableView Example
This is a JavaFX TableView
example. This example displays a table view of books with book title and author information.
The TableView
class is defined in the javafx.scene.control
package of JavaFX API. The example uses Java SE 7 and JavaFX 2.2.
This article’s example is built in two steps.
The first has the functions and features:
- Table row represents a book and the two columns (title and author)
- Scroll down the table rows
- Sort the rows by title or author columns
- Reorder and resizing of columns
- Select a row and show the row (book) info as a text message using a change listener
The second adds additional functions and features:
- Edit the table cells and change the title and author data
- Add new book rows, and enter book info
- Delete existing rows
The example has two classes:
FxTableViewExample.java
: This is the main program with GUI, application logic and the data.Book.java
: This represents the book properties for the table view.
The book data for the example is built within the application.
1. The Book Class
This class has two properties – title and author. Both are of String
type. Note the Object
class’s overridden toString()
method returns a string as “Book title, by Author name” (for example, “The Hobbit, by J.R.R. Tolkien”).
Book.java
import javafx.beans.property.SimpleStringProperty; public class Book { private SimpleStringProperty title; private SimpleStringProperty author; public Book () { } public Book (String s1, String s2) { title = new SimpleStringProperty(s1); author = new SimpleStringProperty(s2); } public String getTitle() { return title.get(); } public void setTitle(String s) { title.set(s); } public String getAuthor() { return author.get(); } public void setAuthor(String s) { author.set(s); } @Override public String toString() { return (title.get() + ", by " + author.get()); } }
2. The TableView Application – Step 1
This is the main program. This:
- Constructs the GUI
- Creates the book data
- Displays the book info in the table view
- Allows row selection
The detailed description follows the code below.
2.1 The Code
FxTableViewExample.java
import javafx.application.Application; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.layout.VBox; import javafx.scene.layout.HBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.scene.paint.Color; import javafx.scene.control.Label; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.TableColumn; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import java.util.List; import java.util.ArrayList; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; public class FxTableViewExample1 extends Application { private TableView table; private ObservableList data; private Text actionStatus; public static void main(String [] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Table View Example 1"); // Books label Label label = new Label("Books"); label.setTextFill(Color.DARKBLUE); label.setFont(Font.font("Calibri", FontWeight.BOLD, 36)); HBox hb = new HBox(); hb.setAlignment(Pos.CENTER); hb.getChildren().add(label); // Table view, data, columns and properties table = new TableView(); data = getInitialTableData(); table.setItems(data); TableColumn titleCol = new TableColumn("Title"); titleCol.setCellValueFactory(new PropertyValueFactory("title")); TableColumn authorCol = new TableColumn("Author"); authorCol.setCellValueFactory(new PropertyValueFactory("author")); table.getColumns().setAll(titleCol, authorCol); table.setPrefWidth(450); table.setPrefHeight(300); table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); table.getSelectionModel().selectedIndexProperty().addListener( new RowSelectChangeListener()); // Status message text actionStatus = new Text(); actionStatus.setFill(Color.FIREBRICK); // Vbox VBox vbox = new VBox(20); vbox.setPadding(new Insets(25, 25, 25, 25));; vbox.getChildren().addAll(hb, table, actionStatus); // Scene Scene scene = new Scene(vbox, 500, 475); // w x h primaryStage.setScene(scene); primaryStage.show(); // Select the first row table.getSelectionModel().select(0); Book book = table.getSelectionModel().getSelectedItem(); actionStatus.setText(book.toString()); } // start() private class RowSelectChangeListener implements ChangeListener { @Override public void changed(ObservableValue ov, Number oldVal, Number newVal) { int ix = newVal.intValue(); if ((ix = data.size())) { return; // invalid data } Book book = data.get(ix); actionStatus.setText(book.toString()); } } private ObservableList getInitialTableData() { List list = new ArrayList(); list.add(new Book("The Thief", "Fuminori Nakamura")); list.add(new Book("Of Human Bondage", "Somerset Maugham")); list.add(new Book("The Bluest Eye", "Toni Morrison")); list.add(new Book("I Am Ok You Are Ok", "Thomas Harris")); list.add(new Book("Magnificent Obsession", "Lloyd C Douglas")); list.add(new Book("100 Years of Solitude", "Gabriel Garcia Marquez")); list.add(new Book("What the Dog Saw", "Malcolm Gladwell")); list.add(new Book("The Fakir", "Ruzbeh Bharucha")); list.add(new Book("The Hobbit", "J.R.R. Tolkien")); list.add(new Book("Strange Life of Ivan Osokin", "P.D. Ouspensky")); list.add(new Book("The Hunt for Red October", "Tom Clancy")); list.add(new Book("Coma", "Robin Cook")); ObservableList data = FXCollections.observableList(list); return data; } }
2.2. JavaFX Classes Used For GUI
- The
Stage
class is used to construct the main window of the application. - The
VBox
lays out its child controls in a single vertical column. - The
Label
is used to display the “Books” title within the main window. - The
TableView
is used to display a vertical scrollable table of books from which the user can select. - The
Text
is used to display a status message.
The controls (widgets) are placed in the vbox in the following order: the books label, table view and the status text. The table view related code follows.
2.3. Create TableView and Populate with Data
2.3.1 The Data
The table view is populated with data from an ObservableList
collection. The table’s data is created within the program. The getInitialTableData()
method creates Book instances and returns them as ObservableList<Book>
.
2.3.2. The Code
The two instance variables:
private TableView<Book> table; private ObservableList<Book> data;
The following code creates table view for Book data and populates it from an ObservableList collection:
table = new TableView<>(); data = getInitialTableData(); table.setItems(data);
2.4. Define Table Columns
There are two columns – the book title and author. These are the title and author properties defined in the Book
class. The following code creates two table columns and sets properties:
TableColumn titleCol = new TableColumn("Title"); titleCol.setCellValueFactory(new PropertyValueFactory<Book, String>("title")); TableColumn authorCol = new TableColumn("Author"); authorCol.setCellValueFactory(new PropertyValueFactory<Book, String>("author"));
A TableView
is made up of a number of TableColumn
instances. Each TableColumn
is responsible for displaying (and editing) the contents of that column. Table column also contains the properties to size/resize the column width, set header text, sorting the column contents, etc.
In the above code the column header (text shown in the column header area) and the column cell value factory (which is used to populate individual cells in the column) are set.
2.4.1. Add Columns to Table
The following code adds the columns to the table and sets the preferred size for the table. The TableView.CONSTRAINED_RESIZE_POLICY
field ensures that any extra column space in table will be distributed among the visible columns to occupy the table width.
table.getColumns().setAll(titleCol, authorCol); table.setPrefWidth(450); table.setPrefHeight(300); table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
2.5. Add Row Selection Listener
A row selection listener, of the type ChangeListener
is attached to the table view:
table.getSelectionModel().selectedIndexProperty().addListener(new RowSelectChangeListener());
When a table row is selected, the row’s book title and author name are displayed in the status text.
2.6. Other Properties
The following are the default properties of the table view:
- Scrolling: As the table rows grow more than the height of the table, the table gets a scroller to scroll the table rows.
- Sorting: The table rows can be sorted by a column, for example by title column. Click the column header to sort in ascending order and click again to sort in descending order.
- Reorder and resizing of columns: The column width can be resized by moving the column separator. The column position can be changed by dragging the column header to a required position.
- Table cell editing: The table cells are not editable (read only), by default.
These property functions can be observed in the running example.
2.7. The GUI
3. The TableView Application – Step 2
The table view example program is enhanced to have editable table cells and functions to add, update or delete table rows.
3.1. Editable Table Cells
The following code makes the table cells of title column editable:
table.setEditable(true); titleCol.setCellFactory(TextFieldTableCell.forTableColumn()); titleCol.setOnEditCommit(new EventHandler<CellEditEvent>() { @Override public void handle(CellEditEvent t) { ((Book) t.getTableView().getItems().get( t.getTablePosition().getRow())).setTitle(t.getNewValue()); } }); ...
This user can click a cell of a selected row, and the cell becomes editable (like a text field). The data in the cell can be changed. Note that after changing the data it is required to press the <Enter> keyboard key to make the data permanent.
3.2. Add New Rows
A Button
control is added to the GUI for adding a new row. The button is associated with an event handler.
The user clicks the Add button. The action creates a new Book instance with empty properties and adds it to the table data model. The new row is added to the table view. Then, the table view’s TableViewSelectionModel
and TableViewFocusModel
API allows the program to select and focus on the newly added row. The new row cells can be edited as needed.
3.2.1. About Event Handler
An event handler of type ActionEvent
is used as a button’s action event handler. The interface EventHandler<ActionEvent>
is implemented for this purpose. The button’s handler property is set as button.setOnaction(someHandler)
. This is common for both buttons in this example – add and delete.
3.3. Delete Rows
A Button
control is added to the GUI for deleting a selected row. The button is associated with an event handler.
The user clicks the Delete button. The action deletes the selected row from the table and the book is deleted from the table data model.
3.4. The GUI
NOTE: Note the last row of the table. It is a new row being edited; the title column value is already entered (“The Heart’s Code”) and the author column shows the cell being edited.
3.5. The Code
FxTableViewExample2.java
import javafx.application.Application; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.layout.VBox; import javafx.scene.layout.HBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.scene.paint.Color; import javafx.scene.control.Label; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.TableColumn; import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.control.TableColumn.CellEditEvent; import javafx.scene.control.Button; import javafx.geometry.Pos; import javafx.geometry.Insets; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import java.util.List; import java.util.ArrayList; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.EventHandler; public class FxTableViewExample2 extends Application { private TableView table; private ObservableList data; private Text actionStatus; public static void main(String [] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Table View Example 2"); // Books label Label label = new Label("Books"); label.setTextFill(Color.DARKBLUE); label.setFont(Font.font("Calibri", FontWeight.BOLD, 36)); HBox labelHb = new HBox(); labelHb.setAlignment(Pos.CENTER); labelHb.getChildren().add(label); // Table view, data, columns and properties table = new TableView(); data = getInitialTableData(); table.setItems(data); table.setEditable(true); TableColumn titleCol = new TableColumn("Title"); titleCol.setCellValueFactory(new PropertyValueFactory("title")); titleCol.setCellFactory(TextFieldTableCell.forTableColumn()); titleCol.setOnEditCommit(new EventHandler<CellEditEvent>() { @Override public void handle(CellEditEvent t) { ((Book) t.getTableView().getItems().get( t.getTablePosition().getRow()) ).setTitle(t.getNewValue()); } }); TableColumn authorCol = new TableColumn("Author"); authorCol.setCellValueFactory(new PropertyValueFactory("author")); authorCol.setCellFactory(TextFieldTableCell.forTableColumn()); authorCol.setOnEditCommit(new EventHandler<CellEditEvent>() { @Override public void handle(CellEditEvent t) { ((Book) t.getTableView().getItems().get( t.getTablePosition().getRow()) ).setAuthor(t.getNewValue()); } }); table.getColumns().setAll(titleCol, authorCol); table.setPrefWidth(450); table.setPrefHeight(300); table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); table.getSelectionModel().selectedIndexProperty().addListener( new RowSelectChangeListener()); // Add and delete buttons Button addbtn = new Button("Add"); addbtn.setOnAction(new AddButtonListener()); Button delbtn = new Button("Delete"); delbtn.setOnAction(new DeleteButtonListener()); HBox buttonHb = new HBox(10); buttonHb.setAlignment(Pos.CENTER); buttonHb.getChildren().addAll(addbtn, delbtn); // Status message text actionStatus = new Text(); actionStatus.setFill(Color.FIREBRICK); // Vbox VBox vbox = new VBox(20); vbox.setPadding(new Insets(25, 25, 25, 25));; vbox.getChildren().addAll(labelHb, table, buttonHb, actionStatus); // Scene Scene scene = new Scene(vbox, 500, 550); // w x h primaryStage.setScene(scene); primaryStage.show(); // Select the first row table.getSelectionModel().select(0); Book book = table.getSelectionModel().getSelectedItem(); actionStatus.setText(book.toString()); } // start() private class RowSelectChangeListener implements ChangeListener { @Override public void changed(ObservableValue ov, Number oldVal, Number newVal) { int ix = newVal.intValue(); if ((ix = data.size())) { return; // invalid data } Book book = data.get(ix); actionStatus.setText(book.toString()); } } private ObservableList getInitialTableData() { List list = new ArrayList(); list.add(new Book("The Thief", "Fuminori Nakamura")); list.add(new Book("Of Human Bondage", "Somerset Maugham")); list.add(new Book("The Bluest Eye", "Toni Morrison")); list.add(new Book("I Am Ok You Are Ok", "Thomas Harris")); list.add(new Book("Magnificent Obsession", "Lloyd C Douglas")); list.add(new Book("100 Years of Solitude", "Gabriel Garcia Marquez")); list.add(new Book("What the Dog Saw", "Malcolm Gladwell")); ObservableList data = FXCollections.observableList(list); return data; } private class AddButtonListener implements EventHandler { @Override public void handle(ActionEvent e) { // Create a new row after last row Book book = new Book("...", "..."); data.add(book); int row = data.size() - 1; // Select the new row table.requestFocus(); table.getSelectionModel().select(row); table.getFocusModel().focus(row); actionStatus.setText("New book: Enter title and author. Press ."); } } private class DeleteButtonListener implements EventHandler { @Override public void handle(ActionEvent e) { // Get selected row and delete int ix = table.getSelectionModel().getSelectedIndex(); Book book = (Book) table.getSelectionModel().getSelectedItem(); data.remove(ix); actionStatus.setText("Deleted: " + book.toString()); // Select a row if (table.getItems().size() == 0) { actionStatus.setText("No data in table !"); return; } if (ix != 0) { ix = ix -1; } table.requestFocus(); table.getSelectionModel().select(ix); table.getFocusModel().focus(ix); } } }
4. Download Java Source Code
This was an example of javafx.scene.control.TableView
You can download the full source code of this example here: JavaFxTableViewExample.zip
Thanks for sharing, i want custom tableview with set imageview
Love the article! However, whenever I try to load data into the table from a file, the table says the author column is always gonna be null; as in it only loads the title. However, if I go into the text file, everything is there…