A JTable displays data using rows and columns.
A JTable does not store data. It only displays data.
JTable uses a model to store the data, the number of columns, and the number of rows.
An instance of the TableModel interface represents the model for a JTable.
The DefaultTableModel class is an implementation of the TableModel interface.
When we use the default constructor of the JTable class, Java sets an instance of the DefaultTableModel class as its model.
If we want to add or remove columns/rows, we must work with its model. we can get the reference of the model of a JTable using its getModel() method.
Let's add two rows and three columns to the table.
DefaultTableModel tableModel = (DefaultTableModel)table.getModel(); // Set the number of rows to 2 tableModel.setRowCount(2); // Set the number of columns to 3 tableModel.setColumnCount(3);
To set the value for a cell in the table, use the setValueAt(Object data, int row, int column) method of the table's model or the table to set a value in its cell.
The following code sets the value at (0, 0) in the table's model.
tableModel.setValueAt("new value", 0, 0);
Set the value at (0, 0) in the table. Works the same as setting the value using the table's model
table.setValueAt("new value", 0, 0);
To support scroll we need to we add the table to a JScrollPane.
The labels for the column headers are set as A, B, and C and we can double-click any cell to start editing the value in the cell.
To get the value in a cell, use the getValueAt(int row, int column) method of the table's model or the JTable.
We can add more columns or rows to the JTable by using the addColumn() and addRow() methods of the DefaultTableModel class.
We can use the removeRow(int row) method of the its model class to remove a row from the JTable.
To set custom labels for column headers using the model's setColumnIdentifiers() method as follows:
// Store the column headers in an array Object[] columnHeaderLabels = new Object[]{"Name", "DOB", "Gender"}; // Set the column headers for the table using its model tableModel.setColumnIdentifiers(columnHeaderLabels);
We can create a JTable with two rows and three columns as shown:
JTable table = new JTable(2, 3);
Two other constructors for the JTable allows us to set the number of rows and columns, and data.
JTable(Object[][] rowData, Object[] columnNames) JTable(Vector rowData, Vector columnNames)
The following code shows how to use the above constructors.
Object[] columnNames = {"ID", "Name", "Gender" } ; Object[][] rowData = new Object[][] { {new Integer(1), "Tom", "Male" }, {new Integer(2), "Jane", "Female"} }; // Create a JTable with the data and the column headers JTable table = new JTable(rowData, columnNames);
The TableModel interface defines the model for a JTable. Here is the declaration of the TableModel interface:
public interface TableModel{ public int getRowCount(); public int getColumnCount(); public String getColumnName(int columnIndex); public Class<?> getColumnClass(int columnIndex); public boolean isCellEditable(int rowIndex, int columnIndex); public Object getValueAt(int rowIndex, int columnIndex); public void setValueAt(Object aValue, int rowIndex, int columnIndex); public void addTableModelListener(TableModelListener l); public void removeTableModelListener(TableModelListener l); }
The AbstractTableModel class implements the TableModel interface. It provides an empty implementation for the methods of the TableModel interface.
We have to implement at least the following three methods in custom table model class to get a read-only table model:
public int getRowCount(); public int getColumnCount(); public Object getValueAt(int row, int column);
The DefaultTableModel class inherits from the AbstractTableModel class. It provides a default implementation for all methods in the TableModel interface.
It uses a Vector of Vectors to store the table's data.
The following code implements a simple table model using an array of arrays to store data.
import java.awt.BorderLayout; import java.awt.Container; /*from w ww . j a v a2s .c o m*/ import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; class SimpleTableModel extends AbstractTableModel { private Object[][] data = {}; private String[] columnNames = { "ID", "Name", "Gender" }; private Class[] columnClass = { Integer.class, String.class, String.class }; private Object[][] rowData = new Object[][] { { new Integer(1), "Tom", "Male" }, { new Integer(2), "Jack", "Female" } }; public SimpleTableModel() { } @Override public int getRowCount() { return rowData.length; } @Override public int getColumnCount() { return columnNames.length; } @Override public String getColumnName(int columnIndex) { return columnNames[columnIndex]; } @Override public Class getColumnClass(int columnIndex) { return columnClass[columnIndex]; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { boolean isEditable = true; if (columnIndex == 0) { isEditable = false; // Make the ID column non-editable } return isEditable; } @Override public Object getValueAt(int rowIndex, int columnIndex) { return rowData[rowIndex][columnIndex]; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { rowData[rowIndex][columnIndex] = aValue; } } public class Main extends JFrame { public Main() { this.setDefaultCloseOperation(EXIT_ON_CLOSE); JTable table = new JTable(new SimpleTableModel()); Container contentPane = this.getContentPane(); contentPane.add(new JScrollPane(table), BorderLayout.CENTER); } public static void main(String[] args) { Main bf = new Main(); bf.pack(); bf.setVisible(true); } }
To add data sorting capability, call setAutoCreateRowSorter(true).
We can sort data in a column by clicking the column's header. After we call this method, a JTable will display an up/down arrow as part of a column header to indicate that a column is sorted in ascending or descending order.
We can use a row filter that will hide rows in a JTable based on some criteria.
import java.awt.BorderLayout; import java.awt.Container; /*from ww w . j av a2 s . com*/ import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.RowFilter; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableRowSorter; class SimpleTableModel extends AbstractTableModel { private Object[][] data = {}; private String[] columnNames = { "ID", "Name", "Gender" }; private Class[] columnClass = { Integer.class, String.class, String.class }; private Object[][] rowData = new Object[][] { { new Integer(1), "Tom", "Male" }, { new Integer(2), "Jack", "Female" } }; public SimpleTableModel() { } @Override public int getRowCount() { return rowData.length; } @Override public int getColumnCount() { return columnNames.length; } @Override public String getColumnName(int columnIndex) { return columnNames[columnIndex]; } @Override public Class getColumnClass(int columnIndex) { return columnClass[columnIndex]; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { boolean isEditable = true; if (columnIndex == 0) { isEditable = false; // Make the ID column non-editable } return isEditable; } @Override public Object getValueAt(int rowIndex, int columnIndex) { return rowData[rowIndex][columnIndex]; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { rowData[rowIndex][columnIndex] = aValue; } } public class Main extends JFrame { public Main() { this.setDefaultCloseOperation(EXIT_ON_CLOSE); JTable table = new JTable(new SimpleTableModel()); TableRowSorter sorter = new TableRowSorter(table.getModel()); table.setRowSorter(sorter); RowFilter<SimpleTableModel, Integer> IDFilter = new RowFilter<SimpleTableModel, Integer>() { @Override public boolean include( Entry<? extends SimpleTableModel, ? extends Integer> entry) { SimpleTableModel model = entry.getModel(); int rowIndex = entry.getIdentifier().intValue(); Integer ID = (Integer) model.getValueAt(rowIndex, 0); if (ID.intValue() <= 100) { return false; // Do not show rows with an ID <= 100 } return true; } }; sorter.setRowFilter(IDFilter); Container contentPane = this.getContentPane(); contentPane.add(new JScrollPane(table), BorderLayout.CENTER); } public static void main(String[] args) { Main bf = new Main(); bf.pack(); bf.setVisible(true); } }
The RowFilter is an abstract class and we must override its include() method to specify filter criteria.
RowFilter has several static methods that return RowFilter objects that we can use directly with a RowSorter object.
The following code shows how to create row filters:
To create a filter that will show only rows that starts with "Tom" in the second column (column index = 1)
RowFilter nameFilter = RowFilter.regexFilter("^Tom*", 1);
To create a filter that will show only rows that has a "Female" value in its third column (column index = 2)
RowFilter genderFilter = RowFilter.regexFilter("^Female$", 2);
To create a filter that will show only rows that has 3rd, 5th and 7th columns values starting with "A"
RowFilter anyFilter1 = RowFilter.regexFilter("^A*", 3, 5, 7);
To create a filter that will show only rows that has any column whose value starts with "A"
RowFilter anyFilter2 = RowFilter.regexFilter("^A*");