Header javaperspective.com
JavaPerspective.com  >   Advanced Tutorials  >   1. Advanced GUI Features  >   1.1. Tables

1.1. Tables
Last updated: 1 January 2013.

This tutorial will show you how to create tables in Java.

A table is an instance of the class JTable. It is a component that displays data in a table containing cells as shown in the following figure:


Table


1.1.1. How to create a simple table

The most basic way of creating a table is by invoking one of the following constructors:In the first constructor, rowData is a two-dimensional array of objects containing the rows data and columnNames is an array of objects containing the column names. In the second constructor, rowData is a vector of vectors containing the rows data and columnNames is a vector containing the column names. For example, the code that creates the GUI shown above uses the constructor JTable(Object[][] rowData, Object[] columnNames):

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public final class Tables extends JFrame {

   
private JTable table;

   
public Tables(){
         
init();
          addComponents
();

          setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
          setVisible
(true);
   
}


   
private void addComponents() {
         
// Set up the array containing the column names
         
Object[] columnNames = {"River system", "Continent", "Length (miles)", "Drainage basin (sq. miles)", "Discharge (cu. meters per second)"};

         
// Set up the array containing the data
         
Object[][] rowData = {
                      {
"Nile", "Africa", new Integer(4180), new Integer(1170000), new Integer(1584)},
                     
{"Amazon", "South America", new Integer(3920), new Integer(2270000), new Integer(180000)},
                     
{"Yangtze", "Asia", new Integer(3964), new Integer(698000), new Integer(35000)},
                     
{"Mississippi - Missouri", "North America", new Integer(3870), new Integer(1247000), new Integer(17545)},
                     
{"Ob", "Asia", new Integer(3459), new Integer(1154000), new Integer(12600)},
                     
{"Yenisei - Angara", "Asia", new Integer(3440), new Integer(996000), new Integer(19600)},
                     
{"Yellow", "Asia", new Integer(3395), new Integer(290000), new Integer(1365)},
                     
{"Congo", "Africa", new Integer(2900), new Integer(1440000), new Integer(42000)},
                     
{"Amur", "Asia", new Integer(2800), new Integer(730000), new Integer(12500)},
                     
{"Parana", "South America", new Integer(2795), new Integer(1197000), new Integer(19500)},
                     
{"Lena", "Asia", new Integer(2734), new Integer(961000), new Integer(16400)},
                     
{"Mackenzie", "North America", new Integer(2640), new Integer(697000), new Integer(7500)},
                     
{"Niger", "Africa", new Integer(2590), new Integer(850000), new Integer(5700)}
          }
;

         
// Create the table
         
table = new JTable(rowData, columnNames);

         
// Set the width of each column
         
table.getColumnModel().getColumn(0).setPreferredWidth(80);
          table.getColumnModel
().getColumn(1).setPreferredWidth(50);
          table.getColumnModel
().getColumn(2).setPreferredWidth(50);
          table.getColumnModel
().getColumn(3).setPreferredWidth(100);
          table.getColumnModel
().getColumn(4).setPreferredWidth(150);

         
// Wrap a JScrollPane around the table
         
JScrollPane scrollPane = new JScrollPane(table);

         
// Add the JScrollPane to the JFrame
         
add(scrollPane);
   
}


   
private void init() {
         
try{
               
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
         
}
         
catch(Exception e){
               
e.printStackTrace();
         
}
         
setTitle("Tables");
          setSize
(800, 250);
          setLocationRelativeTo
(null);
   
}


   
public static void main(String[] args){
         
SwingUtilities.invokeLater(new Runnable() {
               
public void run() {
                     
new Tables();
               
}
          })
;
   
}
}

Every table is associated with a table model (an object that implements the interface TableModel). The purpose of a table model is to handle the data of a table. If you don't provide a table model when creating a table, an instance of the class DefaultTableModel is automatically created to handle the table's data.

The constructors JTable(Object[][] rowData, Object[] columnNames) and JTable(Vector rowData, Vector columnNames) do not take a table model argument. Consequently, a table created with one of these two constructors is automatically associated with a DefaultTableModel instance. Although DefaultTableModel may fit the need in many cases, it has the following limitations: These limitations can be overcome if you provide a table model as explained in the following section.


1.1.2. How to implement a table model

A table model is an object that implements the interface TableModel. A convenient way to implement a table model is to subclass the abstract class AbstractTableModel which implements all the methods of the interface TableModel except the following:If you create a subclass of the class AbstractTableModel, you must implement these methods. Naturally, you can implement other methods of the interface TableModel as well. As an example, in the code below, I am creating a subclass of the class AbstractTableModel in which the 3 mandatory methods are implemented as well as 4 more methods: getColumnClass, getColumnName, isCellEditable and setValueAt.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.table.AbstractTableModel;

public final class MyTableModel extends AbstractTableModel {

   
private List<String> columnNames;
   
private Map<Integer, List<Object>> rowData;

   
public MyTableModel() {
         
// Set up the list containing the column names
         
columnNames = new ArrayList<String>();
          columnNames.add
("River system");
          columnNames.add
("Continent");
          columnNames.add
("Length (miles)");
          columnNames.add
("Drainage basin (sq. miles)");
          columnNames.add
("Discharge (cu. meters per second)");

         
// Set up the HashMap containing the data (the HashMap keys are integers and the HashMap values are lists of objects)
         
rowData = new HashMap<Integer, List<Object>>();
          rowData.put
(0, Arrays.asList(new Object[]{"Nile", "Africa", new Integer(4180), new Integer(1170000), new Integer(1584)}));
          rowData.put
(1, Arrays.asList(new Object[]{"Amazon", "South America", new Integer(3920), new Integer(2270000), new Integer(180000)}));
          rowData.put
(2, Arrays.asList(new Object[]{"Yangtze", "Asia", new Integer(3964), new Integer(698000), new Integer(35000)}));
          rowData.put
(3, Arrays.asList(new Object[]{"Mississippi - Missouri", "North America", new Integer(3870), new Integer(1247000), new Integer(17545)}));
          rowData.put
(4, Arrays.asList(new Object[]{"Ob", "Asia", new Integer(3459), new Integer(1154000), new Integer(12600)}));
          rowData.put
(5, Arrays.asList(new Object[]{"Yenisei - Angara", "Asia", new Integer(3440), new Integer(996000), new Integer(19600)}));
          rowData.put
(6, Arrays.asList(new Object[]{"Yellow", "Asia", new Integer(3395), new Integer(290000), new Integer(1365)}));
          rowData.put
(7, Arrays.asList(new Object[]{"Congo", "Africa", new Integer(2900), new Integer(1440000), new Integer(42000)}));
          rowData.put
(8, Arrays.asList(new Object[]{"Amur", "Asia", new Integer(2800), new Integer(730000), new Integer(12500)}));
          rowData.put
(9, Arrays.asList(new Object[]{"Parana", "South America", new Integer(2795), new Integer(1197000), new Integer(19500)}));
          rowData.put
(10, Arrays.asList(new Object[]{"Lena", "Asia", new Integer(2734), new Integer(961000), new Integer(16400)}));
          rowData.put
(11, Arrays.asList(new Object[]{"Mackenzie", "North America", new Integer(2640), new Integer(697000), new Integer(7500)}));
          rowData.put
(12, Arrays.asList(new Object[]{"Niger", "Africa", new Integer(2590), new Integer(850000), new Integer(5700)}));
   
}


   
public Class getColumnClass(int columnIndex) {
         
return getValueAt(0, columnIndex).getClass();
   
}

   
public int getColumnCount() {
         
return columnNames.size();
   
}

   
public String getColumnName(int columnIndex) {
         
return columnNames.get(columnIndex);
   
}

   
public int getRowCount() {
         
return rowData.size();
   
}

   
public Object getValueAt(int rowIndex, int columnIndex) {
         
return rowData.get(rowIndex).get(columnIndex);
   
}

   
public boolean isCellEditable(int rowIndex, int columnIndex){
         
if(columnIndex == 0 || columnIndex == 1)
               
return false;

         
return true;
   
}

   
public void setValueAt(Object aValue, int rowIndex, int columnIndex){
         
rowData.get(rowIndex).set(columnIndex, aValue);
          fireTableCellUpdated
(rowIndex, columnIndex);
   
}

}

Implementing a table model gives you much more control over the table's data. For example, the method getValueAt allows you to retrieve the value of each cell individually. In the code above, the values are taken from a HashMap but they could have been taken from a database.

The method getColumnClass tells the table about the data type of each column. If that method is not implemented, all the cells of the table are treated as strings. For example, all the cells are left aligned as you can see in the figure showing the table at the beginning of this tutorial. Now that the method getColumnClass is implemented, cells containing integers will be right aligned. Likewise, if the table contained values of type Boolean, they would be displayed as check boxes, instead of being displayed in their string representation (true or false).

I also implemented the method isCellEditable to prevent the user from editing the cells in the two first columns.

Last but not least, the method setValueAt lets you take into account the changes made by the user in the table. In this example, every time the user changes the value of a cell, the HashMap is updated and a table cell update event is fired by the call fireTableCellUpdated(rowIndex, columnIndex). Such a call is necessary because data change events are not automatically fired by subclasses of the class AbstractTableModel. If you are using DefaultTableModel, you don't need to fire data change events explicitly since such events are automatically fired when they occur. For more information about event handling, please refer to the API documentation of the class AbstractTableModel.

The class Tables which builds the GUI now uses an instance of the class MyTableModel. The code follows:

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public final class Tables extends JFrame {

   
private MyTableModel myTableModel;
   
private JTable table;

   
public Tables(){
         
init();
          addComponents
();

          setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
          setVisible
(true);
   
}


   
private void addComponents() {
         
// Create the table model
         
myTableModel = new MyTableModel();

         
// Create the table
         
table = new JTable(myTableModel);

         
// Set the width of each column
         
table.getColumnModel().getColumn(0).setPreferredWidth(80);
          table.getColumnModel
().getColumn(1).setPreferredWidth(50);
          table.getColumnModel
().getColumn(2).setPreferredWidth(50);
          table.getColumnModel
().getColumn(3).setPreferredWidth(100);
          table.getColumnModel
().getColumn(4).setPreferredWidth(150);

         
// Wrap a JScrollPane around the table
         
JScrollPane scrollPane = new JScrollPane(table);

         
// Add the JScrollPane to the JFrame
         
add(scrollPane);
   
}


   
private void init() {
         
try{
               
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
         
}
         
catch(Exception e){
               
e.printStackTrace();
         
}
         
setTitle("Tables");
          setSize
(800, 250);
          setLocationRelativeTo
(null);
   
}


   
public static void main(String[] args){
         
SwingUtilities.invokeLater(new Runnable() {
               
public void run() {
                     
new Tables();
               
}
          })
;
   
}
}

Note that instead of subclassing AbstractTableModel, you can subclass DefaultTableModel if you are not interested in implementing the methods getColumnClass, getColumnName, ... However, such a subclass would be unnecessary unless you want to separate the code that defines the table's data from the code that builds the GUI. As an example, the class MyDefaultTableModel shown below is a subclass of the class DefaultTableModel:

import javax.swing.table.DefaultTableModel;

public final class MyDefaultTableModel extends DefaultTableModel {

   
public MyDefaultTableModel() {
         
// Set up the array containing the column names
         
Object[] columnNames = {"River system", "Continent", "Length (miles)", "Drainage basin (sq. miles)", "Discharge (cu. meters per second)"};

         
// Set up the array containing the data
         
Object[][] rowData = {
                      {
"Nile", "Africa", new Integer(4180), new Integer(1170000), new Integer(1584)},
                     
{"Amazon", "South America", new Integer(3920), new Integer(2270000), new Integer(180000)},
                     
{"Yangtze", "Asia", new Integer(3964), new Integer(698000), new Integer(35000)},
                     
{"Mississippi - Missouri", "North America", new Integer(3870), new Integer(1247000), new Integer(17545)},
                     
{"Ob", "Asia", new Integer(3459), new Integer(1154000), new Integer(12600)},
                     
{"Yenisei - Angara", "Asia", new Integer(3440), new Integer(996000), new Integer(19600)},
                     
{"Yellow", "Asia", new Integer(3395), new Integer(290000), new Integer(1365)},
                     
{"Congo", "Africa", new Integer(2900), new Integer(1440000), new Integer(42000)},
                     
{"Amur", "Asia", new Integer(2800), new Integer(730000), new Integer(12500)},
                     
{"Parana", "South America", new Integer(2795), new Integer(1197000), new Integer(19500)},
                     
{"Lena", "Asia", new Integer(2734), new Integer(961000), new Integer(16400)},
                     
{"Mackenzie", "North America", new Integer(2640), new Integer(697000), new Integer(7500)},
                     
{"Niger", "Africa", new Integer(2590), new Integer(850000), new Integer(5700)}
          }
;
         
         
// Set the data vector
         
setDataVector(rowData, columnNames);
   
}

}


You are here :  JavaPerspective.com  >   Advanced Tutorials  >   1. Advanced GUI Features  >   1.1. Tables
Next tutorial :  JavaPerspective.com  >   Advanced Tutorials  >   1. Advanced GUI Features  >   1.2. Trees

Copyright © 2013. JavaPerspective.com. All rights reserved.  ( Terms | Contact | About ) 
Java is a trademark of Oracle Corporation
Image 1 Image 2 Image 3 Image 4 Image 5 Image 6 Image 7