TableView

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

Download
You can download the full source code of this example here: JavaFxTableViewExample.zip

Prasad Saya

Prasad Saya is a software engineer with over ten years’ experience in application development, maintenance, testing and consulting on various platforms. He is a certified Java and Java EE developer. At present his interest is in developing Java applications. He also has experience working with databases and ERP applications.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Tutorials To Learn
6 years ago

Thanks for sharing, i want custom tableview with set imageview

Cole
Cole
6 years ago

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…

Back to top button