TableColumn.setHeaderRenderer vs. JTableHeader.setDefaultRenderer

41 views Asked by At

While working on a solution for this question, I ran across some strange behaviour with JTableHeader rendering. Rendering output is different when using TableColumn.setHeaderRenderer vs. JTableHeader.setDefaultRenderer with the same renderer. I've confirmed the renderer is being used in both cases. The desired output is produced when using TableColumn.setHeaderRenderer. Can anyone explain why there would be any difference in output? Should one prefer TableColumn.setHeaderRenderer over JTableHeader.setDefaultRenderer? What am i missing?

Invoke the following code with any argument to see the TableColumn.setHeaderRenderer output. No argument will use the JTableHeader.setDefaultRenderer

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class MultiLineHeaderExample extends JFrame
{
    public MultiLineHeaderExample( boolean addRendererToTableColumn )
    {
        super( "Multi-Line Header Example" );

        DefaultTableModel dm = new DefaultTableModel();
        dm.setDataVector( new Object[][]
                {
                    {
                        "a", "b", "c"
                    },
                    {
                        "A", "B", "C"
                    }
                },
            new Object[]
                {
                    "short col", "My First Column, Very Long But Space Separated", "VeryLongNoSpaceSoShouldSomeHowWrap"
                } );

        JTable table = new JTable( dm );
        MultiLineTableHeaderRenderer renderer = new MultiLineTableHeaderRenderer();

        if( addRendererToTableColumn )
        {//if renderer is set on each column, desired rendering is observed
            table.getColumnModel().getColumns().asIterator().forEachRemaining( column -> column.setHeaderRenderer( renderer ) );
        }
        else
        {
            //if set as default renderer for header, incorrect rendering is observed
            table.getTableHeader().setDefaultRenderer( renderer );
        }

        JScrollPane scroll = new JScrollPane( table );
        getContentPane().add( scroll );
        setSize( 400, 110 );
        setVisible( true );
    }


    public static final class MultiLineTableHeaderRenderer extends JTextArea implements TableCellRenderer
    {
        public MultiLineTableHeaderRenderer()
        {
            setEditable( false );
            setLineWrap( true );
            setOpaque( false );
            setFocusable( false );
            setWrapStyleWord( true );
            LookAndFeel.installBorder( this, "TableHeader.cellBorder" );
        }

        @Override
        public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column )
        {
            int width = table.getColumnModel().getColumn( column ).getWidth();
            setText( ( String ) value );
            setSize( width, getPreferredSize().height );
            return this;
        }
    }


    public static void main( String[] args )
    {
        SwingUtilities.invokeLater( () ->
        {
            MultiLineHeaderExample frame = new MultiLineHeaderExample( args.length > 0 );
            frame.addWindowListener( new WindowAdapter()
            {
                public void windowClosing( WindowEvent e )
                {
                    System.exit( 0 );
                }
            } );
        } );
    }
}
0

There are 0 answers