0

I use JTable, and here how it's like when I use

enter image description here

As you can see it's show sort arrow. Nice. Now I want to change color of header when filter by this column. I use this code:

private void refreshColumnHeader() {
        // model column "Added on" index always = 2
        JLabel blueLabel = new JLabel(m2DocumentsTableModel.getColumnName(modelColumnIndex), JLabel.CENTER);
        blueLabel.setFont(new Font("SansSerif", Font.PLAIN, 12));
        blueLabel.setBorder(headerBorder);
        TableCellRenderer tableCellRenderer = new JComponentTableCellRenderer();
        TableColumnModel columnModel = m2DocumentsTableView.getColumnModel();
        TableColumn columnAddedOn = columnModel.getColumn(vColIndex);
        if (modelColumnIndex == 1) { // column "Added On"
            if (!dateTimeFilter.hasFilter()) {
                blueLabel.setForeground(foregroundTableHeaderNotFilter);
            } else {
                blueLabel.setForeground(foregroundTableHeaderFilter);
            }
        }
        columnAddedOn.setHeaderRenderer(tableCellRenderer);
        columnAddedOn.setHeaderValue(blueLabel);
    }

But now the arrow is hide.

enter image description here

Alexei
  • 14,350
  • 37
  • 121
  • 240
  • [mcve] please.. – kleopatra Jul 28 '22 at 22:49
  • java doc setHeaderRenderer: _It is the header renderers responsibility to render the sorting indicator. If you are using sorting and specify a renderer your renderer must render the sorting indication._ – kleopatra Jul 29 '22 at 05:19

1 Answers1

1

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:

  1. The wrapped TableCellRenderer must return a JComponent in order to set its foreground property, which should be the color of the text. For example TableCellRenderers which return JLabels are supported (such as DefaultTableCellRenderers). This seems to be the case though, if pre-installed or default renderers are used.
  2. 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 SortKeys 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 SortKeys are returned by the method getSortKeys is implied here). By default the JTable though seems to create a DefaultRowSorter already.
gthanop
  • 3,035
  • 2
  • 10
  • 27