Architecture & DesignUsing JavaFX Tables to Organize Data

Using JavaFX Tables to Organize Data

The TableView component is one of the versatile components frequently used in JavaFX application development. It enables one to visually organize data quickly. A viewer quickly can grasp even the implicit information intended by the information with its tabular representation. This article explores this component from the point of view of data organization and how it can be effectively be used in Java programming.

TableView

The TableView control provides almost equivalent functionality to Swing’s Jtable component. It is designed to represent an unlimited number of rows of data, segmented out into columns. In JavaFX, there is another component, called ListView, which is similar. The only difference is that TableView supports multiple columns whereas ListView has a single column. The features of TableView control are as follows:

  • Because a table is made up of number of columns, each column is represented by the TableColumn class. This class provides a finer control over the column. An instance of this class is responsible for displaying and modifying the content of that column. Therefore, it contains a number of adjustable properties. For example,
    • It can be resized with the width property (minWidth, maxWidth, prefWidth, width).
    • The visibility of the column can be toggled with the visibility property.
    • There are setter and getter methods for column header and text properties.
    • Can display nested columns.
    • There is a context menu the user can right-click to the column header area.
    • Contents are sortable (using comparator, sortable, sortType).
  • There are resizing policies for the table that determine the state of the table when the user resizes the column.
  • Provides support for sorting multiple columns.

Creating a TableView

Let us create an example application to demonstrate how TableView in JavaFX may be used. Firstly, let us introduce the basic of JavaFX TableView in code. Because a table displays data, we’ll create a class that holds the data.

package sample;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Employee {
   private StringProperty name;
   private StringProperty phone;
   private StringProperty email;
   private IntegerProperty salary;
   public Employee(String name, String phone, String email,
         Integer salary) {
      setName(name);
      setPhone(phone);
      setEmail(email);
      setSalary(salary);
   }
   public StringProperty nameProperty(){
      if(name == null)
      name = new SimpleStringProperty();
      return name;
   }
   public StringProperty phoneProperty() {
      if(phone == null)
      phone = new SimpleStringProperty();
      return phone;
   }
   public StringProperty emailProperty() {
      if(email == null)
      email = new SimpleStringProperty();
      return email;
   }
   public IntegerProperty salaryProperty() {
      if(salary == null)
      salary = new SimpleIntegerProperty();
      return salary;
   }
   public void setName(String name)
         { nameProperty().setValue(name);  }
   public String getName()
         { return nameProperty().get();  }
   public void setPhone(String phone)
         {phoneProperty().setValue(phone);}
   public String getPhone()
         { return phoneProperty().get(); }
   public void setEmail(String email)
         { emailProperty().setValue(email);}
   public String getEmail()
         { return emailProperty().get(); }
   public void setSalary(Integer salary)
         { salaryProperty().setValue(salary);}
   public Integer getSalary()
         { return salaryProperty().get(); }
}

Now, let us create the application layout and put the TableView as the only component into the scene.

package sample;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class AppMain extends Application {
   @Override
   public void start(Stage primaryStage)
         throws Exception {
      BorderPane root = new BorderPane();
      root.setPrefSize(600,400);

      final TableView<Employee> employeeTableView =
         new TableView<>();
      employeeTableView.setPrefWidth(500);
      employeeTableView.setItems(dummyEmployees());
      TableColumn<Employee, String> nameCol =
         new TableColumn<>("Name");
      nameCol.setCellValueFactory(
         new PropertyValueFactory<Employee,
            String>("Name"));

      TableColumn<Employee, String> phoneCol =
         new TableColumn<>("Phone");
      phoneCol.setCellValueFactory(
         new PropertyValueFactory<Employee,
            String>("Phone"));

      TableColumn<Employee, String> emailCol =
         new TableColumn<>("Email");
      emailCol.setCellValueFactory(
         new PropertyValueFactory<Employee,
            String>("Email"));

      TableColumn<Employee, Integer> salaryCol =
         new TableColumn<>("Salary");
      salaryCol.setCellValueFactory(
         new PropertyValueFactory<Employee,
            Integer>("Salary"));

      employeeTableView.getColumns().addAll(nameCol,phoneCol,
         emailCol,salaryCol);
      root.setCenter(employeeTableView);
      Scene scene = new Scene(root);
      primaryStage.setScene(scene);
      primaryStage.setTitle("JavaFX TableView Demonstration");
      primaryStage.show();
   }

   private static ObservableList<Employee> dummyEmployees() {
      ObservableList<Employee> employees =
         FXCollections.observableArrayList();
      employees.add(new Employee("Arko Bannerjee",
         "9876543210","arko@gmail.com", 5600));
      employees.add(new Employee("Subir Sha",
         "8109276354","subir@gmail.com",7200));
      employees.add(new Employee("Karoline Bhatt",
         "638374642","bhatt@gmail.com",3600));
      employees.add(new Employee("Vikas Verma",
         "425637772","vikas@gmail.com",7800));
      employees.add(new Employee("Gurmeet Singh",
         "9876543210","gurmeet@gmail.com",8900));
      employees.add(new Employee("Partho Goel",
         "837743636","partho@gmail.com",5644));
      employees.add(new Employee("Hanish Jaiswal",
         "826355343","hanish@gmail.com",6500));
      employees.add(new Employee("Preety Ahuja",
         "9298366454","preety@gmail.com",7800));
      employees.add(new Employee("Sandip Paul",
         "82773554536","sandip@gmail.com",8600));
      employees.add(new Employee("Sudipto Sarkar",
         "73664552542","sudipto@gmail.com",8200));
      employees.add(new Employee("Bikash Panda",
         "6365344245","panda@gmail.com",8400));
      employees.add(new Employee("Abhronil Sahu",
         "7829293663","sahu@gmail.com",8000));
      employees.add(new Employee("Dilip Das",
         "9283665455","dilip@gmail.com",8100));
      return employees;
   }

   public static void main(String[] args) {
      launch(args);
   }
}

The table is created with the following code:

final TableView<Employee> employeeTableView =
   new TableView<>();

The content of the table is represented by the columns added. Each column also must have a header to visually designate the content of the column. In this example, we’ve set four columns (designated by the property defined in the Employee class).

TableColumn<Employee, String> nameCol =
      new TableColumn<>("Name");
   nameCol.setEditable(true);
   nameCol.setCellValueFactory(
      new PropertyValueFactory<Employee,
         String>("Name"));

Output

The table's content
Figure 1: The table’s content

Next, we’ve set this as the main component of the layout. That’s all we need to do to display some content in the TableView. Functions such as sorting the content do not require any special/additional handling because they are given as a default feature by the component. Also, multiple sorting can be done by holding down the SHIFT key from the keyboard while selecting columns with a mouse click.

Editable Columns in a Table

If we want to create a table that has an editable column, we can do so very easily. When we double-click the editable column, a textbox appears where we can edit the value. To make the change permanent, we need to press the Enter key from the keyboard.

Here is another example with editable columns.

package sample;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class PhoneBook {
   private StringProperty name;
   private StringProperty phone;
   public PhoneBook(String name, String phone) {
      setName(name);
      setPhone(phone);
   }
   public StringProperty nameProperty(){
      if(name == null)
         name = new SimpleStringProperty();
      return name;
   }
   public StringProperty phoneProperty(){
      if(phone == null)
         phone = new SimpleStringProperty();
      return phone;
   }
   public void setName(String name)
      { nameProperty().setValue(name);  }
   public String getName()
      { return nameProperty().get();  }
   public void setPhone(String phone)
      { phoneProperty().setValue(phone);}
   public String getPhone()
      { return phoneProperty().get(); }
   @Override
   public String toString() {
      return getName()+" : "+getPhone();
   }
}

package sample;
import javafx.application.*;
import javafx.beans.value.*;
import javafx.collections.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.scene.layout.*;
import javafx.scene.text.*;
import javafx.stage.*;
public class PhoneBookTable extends Application {
   private TableView<PhoneBook> table;
   private ObservableList data;
   private Text txtStatus;
   @Override
   public void start(Stage primaryStage) {
      primaryStage.setTitle("Table View Demonstration.");
      HBox hb = new HBox();
      hb.setAlignment(Pos.CENTER);
      table = new TableView<>();
      data = dummyData();
      table.setItems(data);
      TableColumn<PhoneBook,String> nameCol = new
         TableColumn<>("Name");
      nameCol.setCellValueFactory(new
         PropertyValueFactory<>("name"));
      TableColumn<PhoneBook,String> phoneCol = new
         TableColumn("Phone");
      phoneCol.setCellValueFactory(new
         PropertyValueFactory<>("phone"));
      table.getColumns().setAll(nameCol, phoneCol);
      table.setPrefWidth(400);
      table.setPrefHeight(250);
      table.setColumnResizePolicy(TableView.
         CONSTRAINED_RESIZE_POLICY);
      table.getSelectionModel().selectedIndexProperty().
            addListener(
         new RowChangeHandler());
      table.setEditable(true);
      phoneCol.setCellFactory(TextFieldTableCell.
         forTableColumn());
      phoneCol.setOnEditCommit(event -> (event.getTableView().
         getItems().get(event.getTablePosition().getRow())).
         setPhone(event.getNewValue()));
      txtStatus = new Text();
      VBox vbox = new VBox(20);
      vbox.setPadding(new Insets(20, 20, 20, 20));;
      vbox.getChildren().addAll(hb, table, txtStatus);
      // W x H
      Scene scene = new Scene(vbox, 450, 375);
      primaryStage.setScene(scene);
      primaryStage.show();
      table.getSelectionModel().select(0);
      PhoneBook pb = table.getSelectionModel().
         getSelectedItem();
      txtStatus.setText(pb.toString());
   }
   private class RowChangeHandler implements
         ChangeListener {
      @Override
      public void changed(ObservableValue ov, Object oldVal,
            Object newVal) {
         int val = ((Number)newVal).intValue();
         if (data.size()<=0) {
            return;
         }
        PhoneBook pb= (PhoneBook) data.get(val);
        txtStatus.setText(pb.toString());
      }
   }
   public ObservableList<PhoneBook> dummyData() {
      ObservableList<PhoneBook> records =
         FXCollections.observableArrayList();
      records.add(new PhoneBook("Mickey Mouse",
         "7894561230"));
      records.add(new PhoneBook("Donald Duck",
         "1234567890"));
      records.add(new PhoneBook("Alladin",
         "7418529630"));
      records.add(new PhoneBook("Zairo",
         "9638527410"));
      records.add(new PhoneBook("Batman",
         "7894561230"));
      records.add(new PhoneBook("Spiderman",
         "852478930"));
      return records;
   }
   public static void main(String [] args) {
      Application.launch(args);
   }
}

Output

One record extracted from the table
Figure 2: One record extracted from the table

Conclusion

The TableView component is quite useful in UI design, especially when we do database programming. JavaFX has made this component versatile although there are some glitches in implementing complex tabular representations. Of course, the usability shown here is just a scratch. More can be accomplished with TableView, as we shall see in future articles.

Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.
Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.

Latest Posts

Related Stories