This can be done by implementing a custom TableCellRenderer
. In particular it would be useful to reuse the default header renderer (because of the sort icons, colors and label) by wrapping it in the custom TableCellRenderer
and just modifying it with the desired foreground color when sorting on that column is detected:
import java.awt.Color;
import java.awt.Component;
import java.util.List;
import java.util.Objects;
import javax.swing.DefaultRowSorter;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class SortedRowHeaderRendererDemo {
private static class SortedRowHeaderRenderer implements TableCellRenderer {
private final TableCellRenderer originalRenderer;
private Color originalForeground;
public SortedRowHeaderRenderer(final TableCellRenderer originalRenderer) {
this.originalRenderer = Objects.requireNonNull(originalRenderer);
originalForeground = null;
}
@Override
public Component getTableCellRendererComponent(final JTable table,
final Object value,
final boolean isSelected,
final boolean hasFocus,
final int row,
final int column) {
final Component original = originalRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (row < 0 && original instanceof JComponent) {
final JComponent originalJComponent = (JComponent) original;
if (originalForeground == null)
originalForeground = originalJComponent.getForeground();
Color fg = originalForeground;
final RowSorter<?> sorter = table.getRowSorter();
if (sorter instanceof DefaultRowSorter) {
final List<? extends SortKey> keys = sorter.getSortKeys();
if (!keys.isEmpty()) {
final SortKey k = keys.get(0); /*The first key is the most
significant one for sorting, ie the last selected sorting column.*/
if (k.getColumn() == table.convertColumnIndexToModel(column)) {
final SortOrder order = k.getSortOrder();
if (SortOrder.ASCENDING.equals(order))
fg = Color.RED;
else if (SortOrder.DESCENDING.equals(order))
fg = Color.GREEN;
//Don't forget here that there are also 'SortOrder.UNSORTED' and 'null' values for 'order'!
}
}
}
originalJComponent.setForeground(fg);
}
return original;
}
}
private static void createAndShowGUI() {
final String addedOnColumn = "Added on";
final JTable table = new JTable(new Object[][] {
new Object[]{"Data001", "Data002", "Data003"},
new Object[]{"Data011", "Data012", "Data013"},
new Object[]{"Data021", "Data022", "Data023"},
new Object[]{"Data031", "Data032", "Data033"},
new Object[]{"Data041", "Data042", "Data043"}
}, new Object[] {"Column1", "Column2", addedOnColumn});
table.setAutoCreateRowSorter(true);
final TableColumn col = table.getColumn(addedOnColumn);
col.setHeaderRenderer(new SortedRowHeaderRenderer(table.getTableHeader().getDefaultRenderer()));
final JFrame frame = new JFrame("Table renderer demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(SortedRowHeaderRendererDemo::createAndShowGUI);
}
}
Features:
A feature (or bug fix rather) is that the code works for tables with column reordering enabled too.
Limitations:
- The wrapped
TableCellRenderer
must return a JComponent
in order to set its foreground property, which should be the color of the text. For example TableCellRenderer
s which return JLabel
s are supported (such as DefaultTableCellRenderer
s). This seems to be the case though, if pre-installed or default renderers are used.
- The
RowSorter
of the table must be of type DefaultRowSorter
(such as a TableRowSorter
) in order to determine if the column is sorted and what is its sort order. That's because the RowSorter
class does not make any guarantees as far as I checked for the order of SortKey
s returned by its getSortKeys
method. On the other hand DefaultRowSorter
guarantees that "Sorting is done based on the current SortKeys, in order" (I am assuming the order in which the SortKey
s are returned by the method getSortKeys
is implied here). By default the JTable
though seems to create a DefaultRowSorter
already.