Detecting a cell selection in a JTable

You can do so with a combination of a ColumnModelListener and a TableSelectionListener. An easier way is to register a MouseListener to your JTable as shown in following example.

Main.java:

import javax.swing.table.*;
import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
 
public class Main extends JFrame {
   public Main() {
      super("TableModel Demonstration");
 
      // create our own custom TableModel
      WineTableModel wineModel = new WineTableModel();
      final JTable table = new JTable(wineModel);
 
      // add rows to our TableModel, each row is represented as a Wine object
      wineModel.addWine(new Wine("Chateau Meyney, St. Estephe", "1994", 18.75f, true));
      wineModel.addWine(new Wine("Chateau Montrose, St. Estephe", "1975", 54.25f, true));
      wineModel.addWine(new Wine("Chateau Gloria, St. Julien", "1993", 22.99f, false));
      wineModel.addWine(new Wine("Chateau Beychevelle, St. Julien", "1970", 61.63f, false));
      wineModel.addWine(new Wine("Chateau La Tour de Mons, Margeaux", "1975", 57.03f, true));
      wineModel.addWine(new Wine("Chateau Brane-Cantenac, Margeaux", "1978", 49.92f, false));
 
      // create the scroll pane and add the table to it. 
      JScrollPane scrollPane = new JScrollPane(table);
 
      // add the scroll pane to this window.
      getContentPane().add(scrollPane, BorderLayout.CENTER);
 
      table.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent e) { 
            if (e.getClickCount() >= 1) {
               int row = table.getSelectedRow();
               int col = table.getSelectedColumn();
 
               if (row == -1 || col == -1) return;
               System.out.println("cell [" + row +","+ col +"]");
            }
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
   }
 
   public static void main(String[] args) {
      Main main = new Main();
      main.pack();
      main.setVisible(true);
   }
}
 
// a simple object that holds data about a particular wine
class Wine {
   private String  name;
   private String  vintage;
   private float   price;
   private boolean inStock;
 
   public Wine(String name, String vintage, float price, boolean inStock) {
      this.name = name;
      this.vintage = vintage;
      this.price = price;
      this.inStock = inStock;
   }
 
   public String getName()     { return name; }
   public String getVintage()  { return vintage; }
   public float  getPrice()    { return price; } 
   public boolean getInStock() { return inStock; }
 
   public String toString() { 
      return "[" + name + ", " + vintage + ", " + price + ", " + inStock + "]"; }
}
 
class WineTableModel extends AbstractTableModel {
   // holds the strings to be displayed in the column headers of our table
   final String[] columnNames = {"Name", "Vintage", "Price", "In stock?"};
 
   // holds the data types for all our columns
   final Class[] columnClasses = {String.class, String.class, Float.class, Boolean.class};
 
   // holds our data
   final Vector data = new Vector();
  
   // adds a row
   public void addWine(Wine w) {
      data.addElement(w);
      fireTableRowsInserted(data.size()-1, data.size()-1);
   }
 
   public int getColumnCount() {
      return columnNames.length;
   }
         
   public int getRowCount() {
      return data.size();
   }
 
   public String getColumnName(int col) {
      return columnNames[col];
   }
 
   public Class getColumnClass(int c) {
      return columnClasses1;
   }
 
   public Object getValueAt(int row, int col) {
      Wine wine = (Wine) data.elementAt(row);
      if (col == 0)      return wine.getName();
      else if (col == 1) return wine.getVintage();
      else if (col == 2) return new Float(wine.getPrice());
      else if (col == 3) return new Boolean(wine.getInStock());
      else return null;
   }
 
   public boolean isCellEditable(int row, int col) {
      return false;
   }
}

Creating a JTable with images in the headers

Courtesy of Nobuo Tamemasa (http://www2.gol.com/users/tame/swing/examples/JTableExamples8.html)



AnimatedIconHeaderExample.java:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.table.*;

/**
 * @version 1.0 06/19/99
 */
public class AnimatedIconHeaderExample extends JFrame {

  public AnimatedIconHeaderExample(){
    super( "AnimatedIconHeader Example" );
    
    final Object[][] data =  new Object[][]{
      {"Leopard","Lycaon"},
      {"Jagur"  ,"Jackal"},
      {"Cheetah","Coyote"},
      {"Puma"   ,"Dingo" },
      {"Lynx"   ,"Fox"   },
      {"Tom"    ,"Hot"  }};
    final String[] column = new String[]{"Cat","Dog"};
    
    ImageIcon[] icons = {new ImageIcon("images/3-119.gif"),
                         new ImageIcon("images/3-6.gif")};
        
    AbstractTableModel model = new AbstractTableModel() {
      public int getColumnCount() { return column.length; }
      public int getRowCount()    { return data.length; }
      public String getColumnName(int col) {
       return column[col]; 
      }
      public Object getValueAt(int row, int col) { 
        return data[row][col]; 
      }
    };
        
    JTable table = new JTable( model );
    JTableHeader header = table.getTableHeader();
    JLabel renderer;
    for (int i=0;i<model.getColumnCount();i++) {
      renderer = (JLabel)table.getColumn(column[i]).getHeaderRenderer();
      renderer.setIcon(icons[i]);
      
      // If you have only one column.
      // icons[i].setImageObserver(header);
      
      icons[i].setImageObserver(new HeaderImageObserver(header, i));
    }
    JScrollPane pane = new JScrollPane(table);
    getContentPane().add(pane);
  }
    
  class HeaderImageObserver implements ImageObserver {
    JTableHeader header;
    int col;
      
    HeaderImageObserver(JTableHeader header, int col) {
      this.header = header;
      this.col    = col;
    }
    
    public boolean imageUpdate(Image img, int flags,
                               int x, int y, int w, int h) {
      if ((flags & (FRAMEBITS|ALLBITS)) != 0) {
        Rectangle rect = header.getHeaderRect(col);
        header.repaint(rect);
      }
      return (flags & (ALLBITS|ABORT)) == 0;
    }
  }    
  
  public static void main(String[] args) {
    AnimatedIconHeaderExample frame = new AnimatedIconHeaderExample();
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    frame.setSize( 300, 140 );
    frame.setVisible(true);
  }
}

Creating borders for JTable columns

Courtesy of Nobuo Tamemasa (http://www2.gol.com/users/tame/swing/examples/JTableExamples7.html)



ColumnBorderTableExample.java:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
 
/**
 * @version 1.0  3/06/99
 */
public class ColumnBorderTableExample extends JFrame {

  public ColumnBorderTableExample() {
    super( "Column Border Example" );
        
    DefaultTableModel dm = new DefaultTableModel(4,10);
    JTable table = new JTable( dm );
    table.setIntercellSpacing(new Dimension(0,0));
    
    Color color = table.getGridColor();
    BorderCellRenderer[] renderers = new BorderCellRenderer[6];
    renderers[0] = createRenderer(color, new Insets(0,0,0,1));
    renderers[1] = createRenderer(color, new Insets(0,1,0,1));
    renderers[2] = createRenderer(color, new Insets(0,1,0,2));
    renderers[3] = createRenderer(color, new Insets(0,2,0,2));
    renderers[4] = createRenderer(color, new Insets(0,2,0,0));
    renderers[5] = createRenderer(Color.red, new Insets(0,1,1,1));
    
    TableColumnModel model = table.getColumnModel();
    model.getColumn(1).setCellRenderer(renderers[0]);
    model.getColumn(2).setCellRenderer(renderers[0]);
    model.getColumn(3).setCellRenderer(renderers[0]);
    model.getColumn(4).setCellRenderer(renderers[1]);
    model.getColumn(5).setCellRenderer(renderers[2]);
    model.getColumn(6).setCellRenderer(renderers[3]);
    model.getColumn(7).setCellRenderer(renderers[4]);
    model.getColumn(8).setCellRenderer(renderers[5]);
    
    JScrollPane scroll = new JScrollPane( table );
    getContentPane().add(scroll, BorderLayout.CENTER);
  }

  public static void main(String[] args) {
    ColumnBorderTableExample frame = new ColumnBorderTableExample();
    frame.addWindowListener( new WindowAdapter() {
      public void windowClosing( WindowEvent e ) {
        System.exit(0);
      }
    });
    frame.setSize( 300, 120 );
    frame.setVisible(true);
  }
  
  private static BorderCellRenderer createRenderer(Color color, Insets insets) {
    BorderCellRenderer renderer = new BorderCellRenderer();
    renderer.setColumnBorder(new LinesBorder(color, insets));    
    return renderer;
  }  
}

BorderCellRenderer.java:

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.border.*;
 
/**
 * @version 1.0 03/06/99
 */
public class BorderCellRenderer extends JLabel
    implements TableCellRenderer {
  protected Border noFocusBorder; 
  protected Border columnBorder; 
 
  public BorderCellRenderer() {
    noFocusBorder = new EmptyBorder(1, 2, 1, 2);
    setOpaque(true);
  }

  public Component getTableCellRendererComponent(JTable table, Object value,
                 boolean isSelected, boolean hasFocus, int row, int column) {
    if (isSelected) {
      setForeground(table.getSelectionForeground());
      setBackground(table.getSelectionBackground());
    } else {
      setForeground(table.getForeground());
      setBackground(table.getBackground());
    }
    setFont(table.getFont());
    
    if (hasFocus) {
      setBorder( UIManager.getBorder("Table.focusCellHighlightBorder") );
      if (table.isCellEditable(row, column)) {
        setForeground( UIManager.getColor("Table.focusCellForeground") );
        setBackground( UIManager.getColor("Table.focusCellBackground") );
      }
    } else {
      if (value instanceof CellBorder) {
        Border border = ((CellBorder)value).getBorder();
        setBorder(border);
      } else {
        if (columnBorder != null) {
          setBorder(columnBorder);
        } else {
          setBorder(noFocusBorder);
        }
      }
    }
    setText((value == null) ? "" : value.toString());        
    return this;
  }
  
  public void setColumnBorder(Border border) {
    columnBorder = border;
  }
  
  public Border getColumnBorder() {
    return columnBorder;
  }
}

CellBorder.java:

import java.awt.*;
import javax.swing.border.*;
 
/**
 * @version 1.0 03/06/99
 */
public interface CellBorder {
   
  public Border getBorder();
  public Border getBorder(int row, int column);
  
  public void setBorder(Border border);
  public void setBorder(Border border, int row, int column);
}

LinesBorder.java:

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
 
/**
 * @version 1.0 03/09/99
 */
public class LinesBorder extends AbstractBorder implements SwingConstants { 
  protected int northThickness;
  protected int southThickness;
  protected int eastThickness;
  protected int westThickness;  
  protected Color northColor;
  protected Color southColor;
  protected Color eastColor;
  protected Color westColor;
  
  public LinesBorder(Color color) {
    this(color, 1);
  }

  public LinesBorder(Color color, int thickness)  {
    setColor(color);
    setThickness(thickness);
  }

  public LinesBorder(Color color, Insets insets)  {
    setColor(color);
    setThickness(insets);
  }

  public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
    Color oldColor = g.getColor();
    
    g.setColor(northColor);
    for (int i = 0; i < northThickness; i++)  {
      g.drawLine(x, y+i, x+width-1, y+i);
    }
    g.setColor(southColor);
    for (int i = 0; i < southThickness; i++)  {
      g.drawLine(x, y+height-i-1, x+width-1, y+height-i-1);
    }
    g.setColor(eastColor);
    for (int i = 0; i < westThickness; i++)  {
      g.drawLine(x+i, y, x+i, y+height-1);
    }
    g.setColor(westColor);
    for (int i = 0; i < eastThickness; i++)  {
      g.drawLine(x+width-i-1, y, x+width-i-1, y+height-1);
    }

    g.setColor(oldColor);
  }

  public Insets getBorderInsets(Component c)       {
    return new Insets(northThickness, westThickness, southThickness, eastThickness);
  }

  public Insets getBorderInsets(Component c, Insets insets) {
    return new Insets(northThickness, westThickness, southThickness, eastThickness);    
  }


  public boolean isBorderOpaque() { return true; }
    
  public void setColor(Color c) {
    northColor = c;
    southColor = c;
    eastColor  = c;
    westColor  = c;
  }
  
  public void setColor(Color c, int direction) {
    switch (direction) {
      case NORTH: northColor = c; break;
      case SOUTH: southColor = c; break;
      case EAST:  eastColor  = c; break;
      case WEST:  westColor  = c; break;
      default: 
    }
  }
    
  public void setThickness(int n) {
    northThickness = n;
    southThickness = n;
    eastThickness  = n;
    westThickness  = n;
  }
    
  public void setThickness(Insets insets) {
    northThickness = insets.top;
    southThickness = insets.bottom;
    eastThickness  = insets.right;
    westThickness  = insets.left;
  }
  
  public void setThickness(int n, int direction) {
    switch (direction) {
      case NORTH: northThickness = n; break;
      case SOUTH: southThickness = n; break;
      case EAST:  eastThickness  = n; break;
      case WEST:  westThickness  = n; break;
      default: 
    }
  }

  public void append(LinesBorder b, boolean isReplace) {
    if (isReplace) {
      northThickness = b.northThickness;
      southThickness = b.southThickness;
      eastThickness  = b.eastThickness;
      westThickness  = b.westThickness;
    } else {
      northThickness = Math.max(northThickness ,b.northThickness);
      southThickness = Math.max(southThickness ,b.southThickness);
      eastThickness  = Math.max(eastThickness  ,b.eastThickness);
      westThickness  = Math.max(westThickness  ,b.westThickness);
    }
  }

  public void append(Insets insets, boolean isReplace) {
    if (isReplace) {
      northThickness = insets.top;
      southThickness = insets.bottom;
      eastThickness  = insets.right;
      westThickness  = insets.left;
    } else {
      northThickness = Math.max(northThickness ,insets.top);
      southThickness = Math.max(southThickness ,insets.bottom);
      eastThickness  = Math.max(eastThickness  ,insets.right);
      westThickness  = Math.max(westThickness  ,insets.left);
    }
  }
}

Disabling selection in my JTable

Look at the three lines of code in this working program to find out how to disallow any selection.

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame 
{
   public Main() {
      super("Table example, Wines from Bordeaux");
 
      Object[][] tabledata = {
            { "Chateau Meyney, St. Estephe", 	   new Integer(1994), "$18.75"},
            { "Chateau Montrose, St. Estephe", 	   new Integer(1975), "$54.25" },
            { "Chateau Gloria, St. Julien", 	   new Integer(1993), "$22.99" },
            { "Chateau Beychevelle, St. Julien",   new Integer(1970), "$61.63" },
            { "Chateau La Tour de Mons, Margeaux", new Integer(1975), "$57.03" },
            { "Chateau Brane-Cantenac, Margeaux",  new Integer(1978), "$49.92" },
      };
 
      String columnheaders[] = { "Wine", "Vintage", "Price" };
 
      JTable table = new JTable(tabledata, columnheaders);
      table.setPreferredScrollableViewportSize(new Dimension(500, 70));
      JScrollPane scrollPane = new JScrollPane(table);
 
      getContentPane().add(scrollPane);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      // disable selection
      table.setRowSelectionAllowed(false);
      table.setColumnSelectionAllowed(false);
      table.setCellSelectionEnabled(false);
 
      pack();
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
}

Detecting row selection in a JTable

Add a MouseListener to the table, and code the mousePressed event like this…

  public void mousePressed(MouseEvent e)
  {
    if ((e.getModifiers() & InputEvent.BUTTON1_MASK)!=0)
    {
      int row = JTable_Name.getSelectedRow();
      System.out.println(row);
    }
  }

Creating a JTable with nested headers

Courtesy of Nobuo Tamemasa (http://www2.gol.com/users/tame/swing/examples/JTableExamples1.html)



GroupableHeaderExample.java:

/* (swing1.1beta3)
 *
 * |-----------------------------------------------------|
 * |        |       Name      |         Language         |
 * |        |-----------------|--------------------------|
 * |  SNo.  |        |        |        |      Others     |
 * |        |   1    |    2   | Native |-----------------|
 * |        |        |        |        |   2    |   3    |  
 * |-----------------------------------------------------|
 * |        |        |        |        |        |        |
 *
 */
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
 
/**
 * @version 1.0 11/09/98
 */
public class GroupableHeaderExample extends JFrame {
 
  GroupableHeaderExample() {
    super( "Groupable Header Example" );
 
    DefaultTableModel dm = new DefaultTableModel();
    dm.setDataVector(new Object[][]{
      {"119","foo","bar","ja","ko","zh"},
      {"911","bar","foo","en","fr","pt"}},
    new Object[]{"SNo.","1","2","Native","2","3"});
 
    JTable table = new JTable( dm ) {
      protected JTableHeader createDefaultTableHeader() {
        return new GroupableTableHeader(columnModel);
      }
    };
    TableColumnModel cm = table.getColumnModel();
    ColumnGroup g_name = new ColumnGroup("Name");
    g_name.add(cm.getColumn(1));
    g_name.add(cm.getColumn(2));
    ColumnGroup g_lang = new ColumnGroup("Language");
    g_lang.add(cm.getColumn(3));
    ColumnGroup g_other = new ColumnGroup("Others");
    g_other.add(cm.getColumn(4));
    g_other.add(cm.getColumn(5));
    g_lang.add(g_other);
    GroupableTableHeader header = (GroupableTableHeader)table.getTableHeader();
    header.addColumnGroup(g_name);
    header.addColumnGroup(g_lang);
    JScrollPane scroll = new JScrollPane( table );
    getContentPane().add( scroll );
    setSize( 400, 120 );   
  }
 
  public static void main(String[] args) {
    GroupableHeaderExample frame = new GroupableHeaderExample();
    frame.addWindowListener( new WindowAdapter() {
      public void windowClosing( WindowEvent e ) {
        System.exit(0);
      }
    });
    frame.setVisible(true);
  }
}

ColumnGroup.java:

import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
 
  
/**
  * ColumnGroup
  *
  * @version 1.0 10/20/98
  * @author Nobuo Tamemasa
  */
 
public class ColumnGroup {
  protected TableCellRenderer renderer;
  protected Vector v;
  protected String text;
  protected int margin=0;
 
  public ColumnGroup(String text) {
    this(null,text);
  }
 
  public ColumnGroup(TableCellRenderer renderer,String text) {
    if (renderer == null) {
      this.renderer = new DefaultTableCellRenderer() {
        public Component getTableCellRendererComponent(JTable table, Object value,
                         boolean isSelected, boolean hasFocus, int row, int column) {
          JTableHeader header = table.getTableHeader();
          if (header != null) {
            setForeground(header.getForeground());
            setBackground(header.getBackground());
            setFont(header.getFont());
          }
          setHorizontalAlignment(JLabel.CENTER);
          setText((value == null) ? "" : value.toString());
          setBorder(UIManager.getBorder("TableHeader.cellBorder"));
          return this;
        }
      };
    } else {
      this.renderer = renderer;
    }
    this.text = text;
    v = new Vector();
  }
 
   
  /**
   * @param obj    TableColumn or ColumnGroup
   */
  public void add(Object obj) {
    if (obj == null) { return; }
    v.addElement(obj);
  }
 
  
  /**
   * @param c    TableColumn
   * @param v    ColumnGroups
   */
  public Vector getColumnGroups(TableColumn c, Vector g) {
    g.addElement(this);
    if (v.contains(c)) return g;    
    Enumeration enum = v.elements();
    while (enum.hasMoreElements()) {
      Object obj = enum.nextElement();
      if (obj instanceof ColumnGroup) {
        Vector groups = 
          (Vector)((ColumnGroup)obj).getColumnGroups(c,(Vector)g.clone());
        if (groups != null) return groups;
      }
    }
    return null;
  }
    
  public TableCellRenderer getHeaderRenderer() {
    return renderer;
  }
    
  public void setHeaderRenderer(TableCellRenderer renderer) {
    if (renderer != null) {
      this.renderer = renderer;
    }
  }
    
  public Object getHeaderValue() {
    return text;
  }
  
  public Dimension getSize(JTable table) {
    Component comp = renderer.getTableCellRendererComponent(
        table, getHeaderValue(), false, false,-1, -1);
    int height = comp.getPreferredSize().height; 
    int width  = 0;
    Enumeration enum = v.elements();
    while (enum.hasMoreElements()) {
      Object obj = enum.nextElement();
      if (obj instanceof TableColumn) {
        TableColumn aColumn = (TableColumn)obj;
        width += aColumn.getWidth();
        width += margin;
      } else {
        width += ((ColumnGroup)obj).getSize(table).width;
      }
    }
    return new Dimension(width, height);
  }
 
  public void setColumnMargin(int margin) {
    this.margin = margin;
    Enumeration enum = v.elements();
    while (enum.hasMoreElements()) {
      Object obj = enum.nextElement();
      if (obj instanceof ColumnGroup) {
        ((ColumnGroup)obj).setColumnMargin(margin);
      }
    }
  }
}

GroupableTableHeader.java:

import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
 
/**
  * GroupableTableHeader
  *
  * @version 1.0 10/20/98
  * @author Nobuo Tamemasa
  */
 
public class GroupableTableHeader extends JTableHeader {
  private static final String uiClassID = "GroupableTableHeaderUI";
  protected Vector columnGroups = null;
    
  public GroupableTableHeader(TableColumnModel model) {
    super(model);
    setUI(new GroupableTableHeaderUI());
    setReorderingAllowed(false);
  }
  
  public void setReorderingAllowed(boolean b) {
    reorderingAllowed = false;
  }
    
  public void addColumnGroup(ColumnGroup g) {
    if (columnGroups == null) {
      columnGroups = new Vector();
    }
    columnGroups.addElement(g);
  }
 
  public Enumeration getColumnGroups(TableColumn col) {
    if (columnGroups == null) return null;
    Enumeration enum = columnGroups.elements();
    while (enum.hasMoreElements()) {
      ColumnGroup cGroup = (ColumnGroup)enum.nextElement();
      Vector v_ret = (Vector)cGroup.getColumnGroups(col,new Vector());
      if (v_ret != null) { 
        return v_ret.elements();
      }
    }
    return null;
  }
   
  public void setColumnMargin() {
    if (columnGroups == null) return;
    int columnMargin = getColumnModel().getColumnMargin();
    Enumeration enum = columnGroups.elements();
    while (enum.hasMoreElements()) {
      ColumnGroup cGroup = (ColumnGroup)enum.nextElement();
      cGroup.setColumnMargin(columnMargin);
    }
  } 
}

GroupableTableHeaderUI.java:

import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.plaf.basic.*;
 
public class GroupableTableHeaderUI extends BasicTableHeaderUI {
  
  public void paint(Graphics g, JComponent c) {
    Rectangle clipBounds = g.getClipBounds();
    if (header.getColumnModel() == null) return;
    ((GroupableTableHeader)header).setColumnMargin();
    int column = 0;
    Dimension size = header.getSize();
    Rectangle cellRect  = new Rectangle(0, 0, size.width, size.height);
    Hashtable h = new Hashtable();
    int columnMargin = header.getColumnModel().getColumnMargin();
    
    Enumeration enumeration = header.getColumnModel().getColumns();
    while (enumeration.hasMoreElements()) {
      cellRect.height = size.height;
      cellRect.y      = 0;
      TableColumn aColumn = (TableColumn)enumeration.nextElement();
      Enumeration cGroups = ((GroupableTableHeader)header).getColumnGroups(aColumn);
      if (cGroups != null) {
        int groupHeight = 0;
        while (cGroups.hasMoreElements()) {
          ColumnGroup cGroup = (ColumnGroup)cGroups.nextElement();
          Rectangle groupRect = (Rectangle)h.get(cGroup);
          if (groupRect == null) {
            groupRect = new Rectangle(cellRect);
            Dimension d = cGroup.getSize(header.getTable());
            groupRect.width  = d.width;
            groupRect.height = d.height;    
            h.put(cGroup, groupRect);
          }
          paintCell(g, groupRect, cGroup);
          groupHeight += groupRect.height;
          cellRect.height = size.height - groupHeight;
          cellRect.y      = groupHeight;
        }
      }      
      cellRect.width = aColumn.getWidth() + columnMargin;
      if (cellRect.intersects(clipBounds)) {
        paintCell(g, cellRect, column);
      }
      cellRect.x += cellRect.width;
      column++;
    }
  }
 
  private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
    TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
    TableCellRenderer renderer = aColumn.getHeaderRenderer();
    Component component = renderer.getTableCellRendererComponent(
      header.getTable(), aColumn.getHeaderValue(),false, false, -1, columnIndex);
    rendererPane.add(component);
    rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
                                cellRect.width, cellRect.height, true);
  }
 
  private void paintCell(Graphics g, Rectangle cellRect,ColumnGroup cGroup) {
    TableCellRenderer renderer = cGroup.getHeaderRenderer();
    Component component = renderer.getTableCellRendererComponent(
      header.getTable(), cGroup.getHeaderValue(),false, false, -1, -1);
    rendererPane.add(component);
    rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
                                cellRect.width, cellRect.height, true);
  }
 
  private int getHeaderHeight() {
    int height = 0;
    TableColumnModel columnModel = header.getColumnModel();
    for(int column = 0; column < columnModel.getColumnCount(); column++) {
      TableColumn aColumn = columnModel.getColumn(column);
      TableCellRenderer renderer = aColumn.getHeaderRenderer();
      Component comp = renderer.getTableCellRendererComponent(
        header.getTable(), aColumn.getHeaderValue(), false, false,-1, column);
      int cHeight = comp.getPreferredSize().height;
      Enumeration enum = ((GroupableTableHeader)header).getColumnGroups(aColumn);      
      if (enum != null) {
        while (enum.hasMoreElements()) {
          ColumnGroup cGroup = (ColumnGroup)enum.nextElement();
          cHeight += cGroup.getSize(header.getTable()).height;
        }
      }
      height = Math.max(height, cHeight);
    }
    return height;
  }
 
  private Dimension createHeaderSize(long width) {
    TableColumnModel columnModel = header.getColumnModel();
    width += columnModel.getColumnMargin() * columnModel.getColumnCount();
    if (width > Integer.MAX_VALUE) {
      width = Integer.MAX_VALUE;
    }
    return new Dimension((int)width, getHeaderHeight());
  }
 
  public Dimension getPreferredSize(JComponent c) {
    long width = 0;
    Enumeration enumeration = header.getColumnModel().getColumns();
    while (enumeration.hasMoreElements()) {
      TableColumn aColumn = (TableColumn)enumeration.nextElement();
      width = width + aColumn.getPreferredWidth();
    }
    return createHeaderSize(width);
  }
}

Create borders for JTable cells

Courtesy of Nobuo Tamemasa (http://www2.gol.com/users/tame/swing/examples/JTableExamples7.html)



CellBorderTableExample.java:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import javax.swing.border.*;
 
/**
 * @version 1.0  3/06/99
 */
public class CellBorderTableExample extends JFrame {

  public CellBorderTableExample() {
    super( &quot;Cell Border Example&quot; );
    
    final Color color = UIManager.getColor(&quot;Table.gridColor&quot;);
        
    DefaultTableModel dm = new DefaultTableModel(12,6) {
      public void setValueAt(Object obj, int row, int col) {
        if (obj instanceof MyData) {
          super.setValueAt(obj, row, col);
        } else {
          MyData myData=null;
          Object oldObject = getValueAt(row, col);
          if (oldObject == null) {
            myData = new MyData(obj, new LinesBorder(color,0));
          } else if (oldObject instanceof MyData) {
            myData = (MyData)oldObject;
          } else {
            System.out.println(&quot;error&quot;);
            return;
          }
          myData.setObject(obj);
          super.setValueAt(myData, row, col);
        }
      }
    };
    
    JTable table = new JTable( dm );
    table.setIntercellSpacing(new Dimension(0,0));
    table.setCellSelectionEnabled(true);
    table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
    table.setDefaultRenderer(Object.class, new BorderCellRenderer());

    JScrollPane scroll = new JScrollPane( table );
    ThicknessPanel thicknessPanel = new ThicknessPanel();
    Box box = new Box(BoxLayout.Y_AXIS);    
    box.add(thicknessPanel);
    box.add(new ButtonPanel(table, thicknessPanel));
    getContentPane().add(scroll, BorderLayout.CENTER);
    getContentPane().add(box,    BorderLayout.EAST);
  }

  public static void main(String[] args) {
    CellBorderTableExample frame = new CellBorderTableExample();
    frame.addWindowListener( new WindowAdapter() {
      public void windowClosing( WindowEvent e ) {
        System.exit(0);
      }
    });
    frame.setSize( 400, 240 );
    frame.setVisible(true);
  }

  
  class ThicknessPanel extends JPanel {    
    JComboBox[] combos;
    
    ThicknessPanel() {
      String[] str = {&quot;top&quot;,&quot;left&quot;,&quot;bottom&quot;,&quot;right&quot;};
      int n = str.length;
      setLayout(new GridLayout(n,2));
      setBorder(new TitledBorder(&quot;Thickness&quot;));
      combos = new JComboBox[n];
      for (int i=0;i&lt;n;i++) {
        combos[i] = new JComboBox(new Object[]{&quot;0&quot;,&quot;1&quot;,&quot;2&quot;,&quot;3&quot;});
        add(new JLabel(str[i]));
        add(combos[i]);
      }
    }
     
    public Insets getThickness() {
      Insets insets = new Insets(0,0,0,0);
      insets.top    = combos[0].getSelectedIndex();      
      insets.left   = combos[1].getSelectedIndex();      
      insets.bottom = combos[2].getSelectedIndex();      
      insets.right  = combos[3].getSelectedIndex();      
      return insets;      
    }
  }

  
  class ButtonPanel extends JPanel {
    JTable table;
    ThicknessPanel thicknessPanel;
    Color color = UIManager.getColor(&quot;Table.gridColor&quot;);
    
    ButtonPanel(JTable table, ThicknessPanel thicknessPanel) {
      this.table = table;
      this.thicknessPanel = thicknessPanel;
      setLayout(new GridLayout(3,1));
      setBorder(new TitledBorder(&quot;Append Lines&quot;));
      final JCheckBox oneBlock = new JCheckBox(&quot;Block&quot;);
      JButton b_and = new JButton(&quot;REPLACE&quot;);
      JButton b_or  = new JButton(&quot;OR&quot;);
      add(oneBlock);
      add(b_and);
      add(b_or);
      b_and.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          setCellBorder(true, oneBlock.isSelected());
        }
      });
      b_or.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          setCellBorder(false, oneBlock.isSelected());
        }
      });
    }  
    
    private void setCellBorder(boolean isReplace, boolean isBlock) {
      boolean isTop,isLeft,isBottom,isRight;
      Insets insets = thicknessPanel.getThickness();
      int[] columns = table.getSelectedColumns();
      int[] rows    = table.getSelectedRows();
      int rowMax    = rows.length;
      int columnMax = columns.length;
      
      for (int i=0;i&lt;rowMax;i++) {
        int row = rows[i];
        isTop    = (i == 0       )? true: false;
        isBottom = (i == rowMax-1)? true: false;
        
        for (int j=0;j&lt;columnMax;j++) {
          int column = columns[j];
          isLeft  = (j == 0          )? true: false;
          isRight = (j == columnMax-1)? true: false;
          
          MyData myData = (MyData)table.getValueAt(row, column);
          if (myData == null) {
            myData = new MyData(&quot;&quot;, new LinesBorder(color,0));
          }
          LinesBorder border = (LinesBorder)myData.getBorder();
          
          if (isBlock) {
            Insets tmp = new Insets(0,0,0,0);
            if (isTop)    tmp.top    = Math.max(tmp.top    ,insets.top);
            if (isLeft)   tmp.left   = Math.max(tmp.left   ,insets.left);
            if (isBottom) tmp.bottom = Math.max(tmp.bottom ,insets.bottom);
            if (isRight)  tmp.right  = Math.max(tmp.right  ,insets.right);
            border.append(tmp, isReplace);
          } else {
            border.append(insets, isReplace);
          }
          
          table.setValueAt(myData, row, column);
        }
      }
      table.clearSelection();
      table.revalidate();
      table.repaint();
    }  
  }
 
  class MyData implements CellBorder {
    private Border border;
    private Object obj;
    
    public MyData(Object obj, Border border) {
      this.obj    = obj;
      this.border = border;
    }
    
    public void setObject(Object obj) {
      this.obj = obj;
    }    
    public String toString() {
      return obj.toString();
    }
    
    // CellBorder   
    public void setBorder(Border border) {
      this.border = border;
    }   
    public Border getBorder() {
      return border;
    }
    public void setBorder(Border border, int row, int col) {}
    public Border getBorder(int row, int col) { return null; }
  }
}

BorderCellRenderer.java:

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.border.*;
 
/**
 * @version 1.0 03/06/99
 */
public class BorderCellRenderer extends JLabel
    implements TableCellRenderer {
  protected Border noFocusBorder; 
  protected Border columnBorder; 
 
  public BorderCellRenderer() {
    noFocusBorder = new EmptyBorder(1, 2, 1, 2);
    setOpaque(true);
  }
 
  public Component getTableCellRendererComponent(JTable table, Object value,
                 boolean isSelected, boolean hasFocus, int row, int column) {
    if (isSelected) {
      setForeground(table.getSelectionForeground());
      setBackground(table.getSelectionBackground());
    } else {
      setForeground(table.getForeground());
      setBackground(table.getBackground());
    }
    setFont(table.getFont());
    
    if (hasFocus) {
      setBorder( UIManager.getBorder(&quot;Table.focusCellHighlightBorder&quot;) );
      if (table.isCellEditable(row, column)) {
        setForeground( UIManager.getColor(&quot;Table.focusCellForeground&quot;) );
        setBackground( UIManager.getColor(&quot;Table.focusCellBackground&quot;) );
      }
    } else {
      if (value instanceof CellBorder) {
        Border border = ((CellBorder)value).getBorder();
        setBorder(border);
      } else {
        if (columnBorder != null) {
          setBorder(columnBorder);
        } else {
          setBorder(noFocusBorder);
        }
      }
    }
    setText((value == null) ? &quot;&quot; : value.toString());        
    return this;
  }
  
  public void setColumnBorder(Border border) {
    columnBorder = border;
  }
   
  public Border getColumnBorder() {
    return columnBorder;
  }
     
}

CellBorder.java:

import java.awt.*;
import javax.swing.border.*;
 
/**
 * @version 1.0 03/06/99
 */
public interface CellBorder {
  
  public Border getBorder();
  public Border getBorder(int row, int column);
  
  public void setBorder(Border border);
  public void setBorder(Border border, int row, int column);
}

LinesBorder.java:

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

/**
 * @version 1.0 03/09/99
 */
public class LinesBorder extends AbstractBorder implements SwingConstants { 
  protected int northThickness;
  protected int southThickness;
  protected int eastThickness;
  protected int westThickness;  
  protected Color northColor;
  protected Color southColor;
  protected Color eastColor;
  protected Color westColor;
  
  public LinesBorder(Color color) {
    this(color, 1);
  }

  public LinesBorder(Color color, int thickness)  {
    setColor(color);
    setThickness(thickness);
  }

  public LinesBorder(Color color, Insets insets)  {
    setColor(color);
    setThickness(insets);
  }

  public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
    Color oldColor = g.getColor();
    
    g.setColor(northColor);
    for (int i = 0; i &lt; northThickness; i++)  {
      g.drawLine(x, y+i, x+width-1, y+i);
    }
    g.setColor(southColor);
    for (int i = 0; i &lt; southThickness; i++)  {
      g.drawLine(x, y+height-i-1, x+width-1, y+height-i-1);
    }
    g.setColor(eastColor);
    for (int i = 0; i &lt; westThickness; i++)  {
      g.drawLine(x+i, y, x+i, y+height-1);
    }
    g.setColor(westColor);
    for (int i = 0; i &lt; eastThickness; i++)  {
      g.drawLine(x+width-i-1, y, x+width-i-1, y+height-1);
    }
 
    g.setColor(oldColor);
  }

  public Insets getBorderInsets(Component c)       {
    return new Insets(northThickness, westThickness, southThickness, eastThickness);
  }
 
  public Insets getBorderInsets(Component c, Insets insets) {
    return new Insets(northThickness, westThickness, southThickness, eastThickness);    
  }
 
  public boolean isBorderOpaque() { return true; }
    
  public void setColor(Color c) {
    northColor = c;
    southColor = c;
    eastColor  = c;
    westColor  = c;
  }
  
  public void setColor(Color c, int direction) {
    switch (direction) {
      case NORTH: northColor = c; break;
      case SOUTH: southColor = c; break;
      case EAST:  eastColor  = c; break;
      case WEST:  westColor  = c; break;
      default: 
    }
  }
    
  public void setThickness(int n) {
    northThickness = n;
    southThickness = n;
    eastThickness  = n;
    westThickness  = n;
  }
    
  public void setThickness(Insets insets) {
    northThickness = insets.top;
    southThickness = insets.bottom;
    eastThickness  = insets.right;
    westThickness  = insets.left;
  }
  
  public void setThickness(int n, int direction) {
    switch (direction) {
      case NORTH: northThickness = n; break;
      case SOUTH: southThickness = n; break;
      case EAST:  eastThickness  = n; break;
      case WEST:  westThickness  = n; break;
      default: 
    }
  }
 
  public void append(LinesBorder b, boolean isReplace) {
    if (isReplace) {
      northThickness = b.northThickness;
      southThickness = b.southThickness;
      eastThickness  = b.eastThickness;
      westThickness  = b.westThickness;
    } else {
      northThickness = Math.max(northThickness ,b.northThickness);
      southThickness = Math.max(southThickness ,b.southThickness);
      eastThickness  = Math.max(eastThickness  ,b.eastThickness);
      westThickness  = Math.max(westThickness  ,b.westThickness);
    }
  }

  public void append(Insets insets, boolean isReplace) {
    if (isReplace) {
      northThickness = insets.top;
      southThickness = insets.bottom;
      eastThickness  = insets.right;
      westThickness  = insets.left;
    } else {
      northThickness = Math.max(northThickness ,insets.top);
      southThickness = Math.max(southThickness ,insets.bottom);
      eastThickness  = Math.max(eastThickness  ,insets.right);
      westThickness  = Math.max(westThickness  ,insets.left);
    }
  }
}

Right-aligning a JTable column

Main.java:

import javax.swing.table.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame 
{
   public Main() {
      super("Table example, Wines from Bordeaux");
 
      Object[][] tabledata = {
            { "Chateau Meyney, St. Estephe", 	   new Integer(1994), "$18.75"},
            { "Chateau Montrose, St. Estephe", 	   new Integer(1975), "$54.25" },
            { "Chateau Gloria, St. Julien", 	   new Integer(1993), "$22.99" },
            { "Chateau Beychevelle, St. Julien",   new Integer(1970), "$61.63" },
            { "Chateau La Tour de Mons, Margeaux", new Integer(1975), "$57.03" },
            { "Chateau Brane-Cantenac, Margeaux",  new Integer(1978), "$49.92" },
      };
 
      String columnheaders[] = { "Wine", "Vintage", "Price" };
 
      JTable table = new JTable(tabledata, columnheaders);
      table.setPreferredScrollableViewportSize(new Dimension(500, 70));
 
      // right align 2nd column
      TableColumnModel columnModel = table.getColumnModel();
      TableColumn column = columnModel.getColumn(1);  
      DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
      renderer.setHorizontalAlignment(JLabel.RIGHT);
      column.setCellRenderer(renderer);
 
      // right align 2nd column when editing
      JTextField tf = new JTextField();
      tf.setHorizontalAlignment(JTextField.RIGHT);
      column.setCellEditor(new DefaultCellEditor(tf));
 
      JScrollPane scrollPane = new JScrollPane(table);
      getContentPane().add(scrollPane);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      pack();
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
}

Detecting a double-click on a row in a JTable

Make sure your class implements the MouseListener interface, and use the following code to detect a double-click on a table row:

public void mouseClicked(MouseEvent e) {
   if (e.getClickCount() == 2) {
      JTable target = (JTable)e.getSource();
      int row = target.getSelectedRow();
      ...
   }
}

Creating a JTable with headers with JTooltips

Courtesy of Nobuo Tamemasa (http://www2.gol.com/users/tame/swing/examples/JTableExamples6.html)



ToolTipHeaderTableExample.java:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

/**
 * @version 1.0 02/25/99
 */
public class ToolTipHeaderTableExample extends JPanel {

  public ToolTipHeaderTableExample(){
    setLayout(new BorderLayout());
    String[] headerStr  = {"default","jw"      ,"ja"      ,"la"   ,"unknown"};
    String[] toolTipStr = {""       ,"Javanese","Japanese","Latin"};
    
    DefaultTableModel dm = new DefaultTableModel(headerStr, 4);
    JTable table = new JTable(dm);
    
    ToolTipHeader header = new ToolTipHeader(table.getColumnModel());
    header.setToolTipStrings(toolTipStr);
    header.setToolTipText("Default ToolTip TEXT");
    table.setTableHeader(header);
    
    JScrollPane pane = new JScrollPane(table);
    add(pane, BorderLayout.CENTER);
  }

  public static void main(String[] args) {
    JFrame f= new JFrame("ToolTipHeaderTable Example");
    f.getContentPane().add(new ToolTipHeaderTableExample(), BorderLayout.CENTER);
    f.setSize(400, 100);
    f.setVisible(true);
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {System.exit(0);}
    });
  }
    
  class ToolTipHeader extends JTableHeader {
    String[] toolTips;
  
    public ToolTipHeader(TableColumnModel model) {
      super(model);
    }
    
    public String getToolTipText(MouseEvent e) {
      int col  = columnAtPoint(e.getPoint());
      int modelCol = getTable().convertColumnIndexToModel(col);
      String retStr;
      try {
        retStr = toolTips[modelCol];
      } catch (NullPointerException ex) {
        retStr = "";
      } catch (ArrayIndexOutOfBoundsException ex) {
        retStr = "";
      }
      if (retStr.length() < 1) {
        retStr = super.getToolTipText(e);
      }
      return retStr;
    }   
    
    public void setToolTipStrings(String[] toolTips) {
      this.toolTips = toolTips;
    } 
  }
}