4

I am trying to get the header on a table to have word wrap. I have managed to do this but the first data row is expanding. The code for the table is:

public class GenerateTable extends JTable {

    private JCheckBox boxSelect = new JCheckBox();
    private JTableHeader hdGen;

    public class LineWrapCellRenderer extends JTextArea implements TableCellRenderer {

        private static final long serialVersionUID = 1L;
        int rowHeight = 0;  // current max row height for this scan
        @Override
        public Component getTableCellRendererComponent(
                JTable table,
                Object value,
                boolean isSelected,
                boolean hasFocus,
                int row,
                int column)
        {
            /*
             * row < 0 means header
             */
            if(row >= 0) {
                setWrapStyleWord(false);
                return this;
            }
            setText((String) value);
            setWrapStyleWord(true);
            setLineWrap(true);
            // current table column width in pixels
            int colWidth = table.getColumnModel().getColumn(column).getWidth();

            // set the text area width (height doesn't matter here)
            setSize(new Dimension(colWidth, 1)); 

            // get the text area preferred height and add the row margin
            int height = getPreferredSize().height + table.getRowMargin();
            // ensure the row height fits the cell with most lines, row = -1 for header
            if (column == 2 || height > rowHeight) {
                table.setRowHeight(row, height);
                rowHeight = height;
            } 
            return this;
        }
    }
    LineWrapCellRenderer lwHeader = new LineWrapCellRenderer();
    public GenerateTable(GenerateTableModel model) {
        super(model);
        this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        /*
         * Select
         */
        TableColumn colSelect = this.getColumnModel().getColumn(0);
        colSelect.setCellEditor(new DefaultCellEditor(boxSelect));
        colSelect.setPreferredWidth(60);
        /*
         * category
         */
        this.getColumnModel().getColumn(1).setResizable(false);
        this.getColumnModel().getColumn(1).setPreferredWidth(200);
        /*
         * Amount values
         */
        for (int i=2;i<model.getColumnCount();i++) {
            colSelect = this.getColumnModel().getColumn(i);
            colSelect.setPreferredWidth(100);
            colSelect.setResizable(false);
            colSelect.setHeaderRenderer(lwHeader);
        }

    }

}

The output is:

enter image description here

I have followed the code through in debug and LineWrapCellRenderer is not being called for the data lines. If I take the code out I get a normal table but no wrap on the header. Is this a recognised problem or am I missing something?

Any help appreciated

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • 01/05/2014 - 31/05/2014 == May/2014 – mKorbel Oct 06 '14 at 10:12
  • What about a static size for the header height? `setSize(new Dimension(colWidth, 26));` In every case a bit of extra room seems needed for the header grid cells' bottom line: `table.setRowHeight(row, height + 2);` – Joop Eggen Oct 06 '14 at 10:21
  • Thanks Joop, I thought about this but still don't understand why the first row of data is expanded by so much. –  Oct 06 '14 at 10:37

1 Answers1

7

You can achieve multi-line headers much easier.

As with many Swing components you can use HTML code. In HTML specify <br> elements to indicate where line breaks / new lines should occur.

For example if you use the following header values (column names):

String[] columnNames = {
    "<html>First<br>column</html>",
    "<html>Second<br>column</html>",
    "<html>Third<br>column</html>"
};

Then the headers will be properly rendered in 2 lines. You don't even need to create/use a custom header renderer, the default header renderer properly handles HTML code.

Note: The header height will be determined by the height of the first column. So you have to use a 2-line HTML value for the first column too. If you only have 1 word for the first column, you may additionally add an empty second line like this: "<html>Select<br>&nbsp;</html>"

icza
  • 389,944
  • 63
  • 907
  • 827