This article shows how to create custom renderers for column headers in a JTable. Here’s a couple of examples of JTable with its column headers customized:

 JTable column header custom renderer basic

A JTable with all column headers customized with a same renderer

 

JTable header multi custom renderers

A JTable with multi renderers for different column headers

Basically we create a custom renderer by writing a class that implements the TableCellRender interface and extends a Swing component (e.g. JLabel) like this:

public class SimpleHeaderRenderer extends JLabel implements TableCellRenderer {

	public SimpleHeaderRenderer() {
		// code to initilize the GUI...
	}

	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {

		// code to customize the GUI based on the parameters

		return this;
	}

}
Then we set this renderer for all column headers in the table like this:

table.getTableHeader().setDefaultRenderer(new SimpleHeaderRenderer());
Or set this renderer for a specific column, e.g. the 3rd column in this example:

table.getColumnModel().getColumn(2).setHeaderRenderer(new SimpleHeaderRenderer());
Now let’s see how to create tables with custom renderers that look like the above screenshots. 

 

1. A simple custom renderer for all column headers

This example shows how to create a custom renderer and apply it for all column headers of a JTable.



Code of the renderer class, SimpleHeaderRenderer.java:

package net.codejava.swing.jtable;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

/**
 * A simple renderer class for JTable component.
 * @author www.codejava.net
 *
 */
public class SimpleHeaderRenderer extends JLabel implements TableCellRenderer {

	public SimpleHeaderRenderer() {
		setFont(new Font("Consolas", Font.BOLD, 14));
		setForeground(Color.BLUE);
		setBorder(BorderFactory.createEtchedBorder());
	}
	
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		setText(value.toString());
		return this;
	}

}
 

Code of a demo program, JTableHeaderRendererSimple.java:

package net.codejava.swing.jtable;

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

/**
 * A Swing program demonstrates how to use a custom renderer for
 * all column headers of a JTable component. 
 * @author www.codejava.net
 *
 */
public class JTableHeaderRendererSimple extends JFrame {
	
	private JTable table;
	
	public JTableHeaderRendererSimple(){
		super("JTable Column Header Custom Renderer Basic");
		
		// constructs the table
		String[] columnNames = new String[] {"Title", "Author", "Publisher", "Published Date", "Pages", "Rating"};
		String[][] rowData = new String[][] {
			{"Effective Java", "Joshua Bloch", "Addision-Wesley", "May 08th 2008", "346", "5"},	
			{"Thinking in Java", "Bruce Eckel", "Prentice Hall", "Feb 26th 2006", "1150", "4"},	
			{"Head First Java", "Kathy Sierra & Bert Bates", "O'Reilly Media", "Feb 09th 2005", "688", "4.5"},	
		};
				
		table = new JTable(rowData, columnNames);
		table.getTableHeader().setDefaultRenderer(new SimpleHeaderRenderer());
		
		add(new JScrollPane(table));
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(640, 150);
		setLocationRelativeTo(null);
	}
	
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				new JTableHeaderRendererSimple().setVisible(true);
			}
		});
	}

}
Output when running the demo program:

JTable column header custom renderer basic

 

2. Multi custom renderers for different column headers

This example shows how to create and apply different renderers for different column headers, for these table headers:

 default JTable column headers

We are going to create a default render for all headers and three different renderers for the three columns “Won”, “Drawn”, and “Lost”.

Code of the default renderer class, DefaultHeaderRenderer.java:

package net.codejava.swing.jtable;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

/**
 * A simple renderer class for JTable component.
 * @author www.codejava.net
 *
 */
public class DefaultHeaderRenderer extends JLabel implements TableCellRenderer {

	public DefaultHeaderRenderer() {
		setFont(new Font("Consolas", Font.BOLD, 14));
		setOpaque(true);
		setForeground(Color.WHITE);
		setBackground(Color.BLACK);
		setBorder(BorderFactory.createEtchedBorder());
	}
	
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		setText(value.toString());
		return this;
	}

}
 

Code of the renderer class for the “Won” column header, WonHeaderRenderer.java:

package net.codejava.swing.jtable;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

/**
 * A simple renderer class for JTable component.
 * @author www.codejava.net
 *
 */
public class WonHeaderRenderer extends JLabel implements TableCellRenderer {

	public WonHeaderRenderer() {
		setFont(new Font("Consolas", Font.BOLD, 14));
		setOpaque(true);
		setForeground(Color.WHITE);
		setBackground(Color.BLUE);
		setBorder(BorderFactory.createEtchedBorder());
	}
	
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		setText(value.toString());
		return this;
	}

}
 

Code of the renderer class for the “Drawn” column header, DrawnHeaderRenderer.java:

package net.codejava.swing.jtable;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

/**
 * A simple renderer class for JTable component.
 * @author www.codejava.net
 *
 */
public class DrawnHeaderRenderer extends JLabel implements TableCellRenderer {

	public DrawnHeaderRenderer() {
		setFont(new Font("Consolas", Font.BOLD, 14));
		setOpaque(true);
		setForeground(Color.BLACK);
		setBackground(Color.YELLOW);
		setBorder(BorderFactory.createEtchedBorder());
	}
	
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		setText(value.toString());
		return this;
	}

}
 

Code of the renderer class for the “Lost” column header, LostHeaderRenderer.java:

package net.codejava.swing.jtable;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

/**
 * A simple renderer class for JTable component.
 * @author www.codejava.net
 *
 */
public class LostHeaderRenderer extends JLabel implements TableCellRenderer {

	public LostHeaderRenderer() {
		setFont(new Font("Consolas", Font.BOLD, 14));
		setOpaque(true);
		setForeground(Color.WHITE);
		setBackground(Color.GRAY);
		setBorder(BorderFactory.createEtchedBorder());
	}
	
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		setText(value.toString());
		return this;
	}

}
 

Code of a demo program, JTableHeaderMultiRenderers.java:

package net.codejava.swing.jtable;

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

/**
 * A Swing program demonstrates how to use multi custom renderers for
 * column headers of a JTable component. 
 * @author www.codejava.net
 *
 */
public class JTableHeaderMultiRenderers extends JFrame {

	private JTable table;
	
	public JTableHeaderMultiRenderers() {
		
		super("JTable Column Header Multi Custom Renderers");
		
		// constructs the table
		String[] columnNames = new String[] {"Position", "Team", "Won", "Drawn", "Lost", "Points"};
		String[][] rowData = new String[][] {
			{"1", "Manchester United", "28", "5", "5", "89"},	
			{"2", "Manchester City", "23", "9", "6", "78"},	
			{"3", "Chelsea", "22", "9", "7", "75"},	
			{"4", "Arsenal", "21", "10", "7", "73"},	
		};
				
		table = new JTable(rowData, columnNames);
		
		table.getTableHeader().setDefaultRenderer(new DefaultHeaderRenderer());
		table.getColumnModel().getColumn(2).setHeaderRenderer(new WonHeaderRenderer());
		table.getColumnModel().getColumn(3).setHeaderRenderer(new DrawnHeaderRenderer());
		table.getColumnModel().getColumn(4).setHeaderRenderer(new LostHeaderRenderer());
				
		add(new JScrollPane(table));
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(640, 150);
		setLocationRelativeTo(null);
	}
	
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				new JTableHeaderMultiRenderers().setVisible(true);
			}
		});
	}	
}
Output when running the demo program:

JTable header multi custom renderers


3. Keeping sort icons

One problem with the custom renderer for column header is that the sort icons (e.g. ascending and descending icons) are lost, even the sorting functionality is still working fine. To overcome this problem, create a renderer class as follows:

package net.codejava.swing.jtable;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

/**
 * A simple renderer class for JTable component, but keep the sort icons.
 * @author www.codejava.net
 *
 */
public class KeepSortIconHeaderRenderer implements TableCellRenderer {
	
	private TableCellRenderer defaultRenderer;
	
	public KeepSortIconHeaderRenderer(TableCellRenderer defaultRenderer) {
		this.defaultRenderer = defaultRenderer;
	}
	
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		Component comp = defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

		if (comp instanceof JLabel) {
			JLabel label = (JLabel) comp;
			label.setFont(new Font("Consolas", Font.BOLD, 14));
			label.setForeground(Color.BLUE);
			label.setBorder(BorderFactory.createEtchedBorder());
		}
		
		return comp;
	}

}
 

The trick here is to update the default renderer (which is usually a JLabel instance) instead of returning a completely new JLabel component. Code to use this renderer is as follows:

  • For all column headers:
    JTableHeader header = table.getTableHeader();
    header.setDefaultRenderer(new KeepSortIconHeaderRenderer(header.getDefaultRenderer()));

    Output:
    Keep sort icons on all column headers
     

  • For a specific column header:  

    TableColumn column = table.getColumnModel().getColumn(2);
    column.setHeaderRenderer(new KeepSortIconHeaderRenderer(table.getTableHeader().getDefaultRenderer()));

    Output:
    Keep sort icons on a custom header renderer 

You can download demo programs in the Attachments section.

 

Related JTable Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (DefaultHeaderRenderer.java)DefaultHeaderRenderer.java[Custom renderer]0.8 kB
Download this file (DrawnHeaderRenderer.java)DrawnHeaderRenderer.java[Custom renderer]0.8 kB
Download this file (DrawnHeaderRendererKeepSortIcon.java)DrawnHeaderRendererKeepSortIcon.java[Custom renderer (keep sort icons)]1 kB
Download this file (JTableHeaderMultiRenderers.java)JTableHeaderMultiRenderers.java[Demo program (multi renderers)]1 kB
Download this file (JTableHeaderMultiRenderersKeepSortIcons.java)JTableHeaderMultiRenderersKeepSortIcons.java[Demo program (multi renderers + keep sort icons)]1 kB
Download this file (JTableHeaderRendererKeepSortIcon.java)JTableHeaderRendererKeepSortIcon.java[Demo program (single renderer + keep sort icons)]1 kB
Download this file (JTableHeaderRendererSimple.java)JTableHeaderRendererSimple.java[Demo program (single renderer)]1 kB
Download this file (KeepSortIconHeaderRenderer.java)KeepSortIconHeaderRenderer.java[Custom renderer (keep sort icons)]1 kB
Download this file (LostHeaderRenderer.java)LostHeaderRenderer.java[Custom renderer]0.8 kB
Download this file (SimpleHeaderRenderer.java)SimpleHeaderRenderer.java[Custom renderer]0.7 kB
Download this file (WonHeaderRenderer.java)WonHeaderRenderer.java[Custom renderer]0.8 kB

Add comment

   


Comments 

#1Jayant2024-01-18 10:43
Thank you very much for your information about the header rendering. I am trying to search column header text of Jtable from one of the search box. I am able to search text but the background color which I have mentioned to highlight searched header cell get highlighted only if I move mouse over header cell.
Can you please help me into this
Quote