I'm trying to implement a custom TableRenderer as described in this tutorial. I'd like to have the renderer line-wrap each text that is to long for the given cell. The idea is, to use a TextArea as renderer, as it supports line wrapping. However, the following code does not behave as expected:
public class LineWrapCellRenderer extends JTextArea implements TableCellRenderer { @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { this.setText((String)value); this.setWrapStyleWord(true); this.setLineWrap(true); return this; } }
I set this renderer with
table.setDefaultRenderer(String.class, new LineWrapCellRenderer());
But the cell entries stay unwrapped. If I add this.setBackground(Color.YELLOW)
to the getTableCellRendererComponent()
method, all cells are yellow as expected, but not wrapped.
Any ideas?
UPDATE: As Michael Borgwardt stated in the comments, the problem is not the line wrap, but the row height: JTables rows are fixed size, so if a cell is getting higher (cause the text is now multi-lined), we have to increase the row height. But how much? I will check if this is worth another SO-question. If not, I will add this solution here.
Update2: The following code will determine the row height (if placed in getTableCellRendererComponent()
):
int fontHeight = this.getFontMetrics(this.getFont()).getHeight(); int textLength = this.getText().length(); int lines = textLength / this.getColumns() +1;//+1, cause we need at least 1 row. int height = fontHeight * lines; table.setRowHeight(row, height);
The problem is that the height of rows in JTable is fixed, so it's not just a matter of having a renderer that wraps; I'm not sure why it doesn't, but if it did, the wrapped text would be cropped - or maybe that's exactly what you're seeing. To adjust row heights, you need to set them individually.
Heres' some code for that:
int rows = 10; int cols = 5; JTable table = new JTable(rows, cols); // Set the 1st row to 60 pixels high table.setRowHeight(0, 60); // Set the height of all rows to 32 pixels high, // regardless if any heights were assigned to particular rows table.setRowHeight(32); // the height of the 1st row is set to 32 pixels high // Returns the preferred height of a row. // The result is equal to the tallest cell in the row. public int getPreferredRowHeight(JTable table, int rowIndex, int margin) { // Get the current default height for all rows int height = table.getRowHeight(); // Determine highest cell in the row for (int c=0; c<table.getColumnCount(); c++) { TableCellRenderer renderer = table.getCellRenderer(rowIndex, c); Component comp = table.prepareRenderer(renderer, rowIndex, c); int h = comp.getPreferredSize().height + 2*margin; height = Math.max(height, h); } return height; } // The height of each row is set to the preferred height of the // tallest cell in that row. public void packRows(JTable table, int margin) { packRows(table, 0, table.getRowCount(), margin); } // For each row >= start and < end, the height of a // row is set to the preferred height of the tallest cell // in that row. public void packRows(JTable table, int start, int end, int margin) { for (int r=0; r<table.getRowCount(); r++) { // Get the preferred height int h = getPreferredRowHeight(table, r, margin); // Now set the row height using the preferred height if (table.getRowHeight(r) != h) { table.setRowHeight(r, h); } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With