Thursday, August 7, 2008

How to wrap text inside cells of a JTable

Introduction

If you wrap the text in the JTable cell, which being wrapped into multiple line as well as row height also automatically to make the complete text area visible. This is class implemented a JTextArea renderer.

TextAreaRenderer.java


/** 
 * @(#)TextAreaRenderer.java 
 */ 
 
import javax.swing.JTable; 
import javax.swing.JTextArea; 
import javax.swing.table.DefaultTableCellRenderer; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 
import javax.swing.table.TableColumnModel; 
import java.awt.Component; 
import java.util.Enumeration; 
import java.util.HashMap; 
import java.util.Map; 
 
/** 
 * The standard class for rendering (displaying) individual cells in a JTable. 
 * This class inherits from JTextArea, a standard component class. 
 * However JTextArea is a multi-line area that displays plain text. 
 * 
 * This class implements TableCellRenderer , i.e. interface. 
 * This interface defines the method required by any object that 
 * would like to be a renderer for cells in a JTable. 
 * 
 * @author Manivel 
 * @see JTable 
 * @see JTextArea 
 */ 
 
public class TextAreaRenderer extends JTextArea implements TableCellRenderer { 
    private final DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); 
 
    // Column heights are placed in this Map 
    private final Map<JTable, Map<Object, Map<Object, Integer>>> tablecellSizes = new HashMap<JTable, Map<Object, Map<Object, Integer>>>(); 
 
    /** 
     * Creates a text area renderer. 
     */ 
    public TextAreaRenderer() { 
        setLineWrap(true); 
        setWrapStyleWord(true); 
    } 
 
    /** 
     * Returns the component used for drawing the cell.  This method is 
     * used to configure the renderer appropriately before drawing. 
     * 
     * @param table      - JTable object 
     * @param value      - the value of the cell to be rendered. 
     * @param isSelected - isSelected   true if the cell is to be rendered with the selection highlighted; 
     *                   otherwise false. 
     * @param hasFocus   - if true, render cell appropriately. 
     * @param row        - The row index of the cell being drawn. 
     * @param column     - The column index of the cell being drawn. 
     * @return - Returns the component used for drawing the cell. 
     */ 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 
                                                   boolean hasFocus, int row, int column) { 
        // set the Font, Color, etc. 
        renderer.getTableCellRendererComponent(table, value, 
                isSelected, hasFocus, row, column); 
        setForeground(renderer.getForeground()); 
        setBackground(renderer.getBackground()); 
        setBorder(renderer.getBorder()); 
        setFont(renderer.getFont()); 
        setText(renderer.getText()); 
 
        TableColumnModel columnModel = table.getColumnModel(); 
        setSize(columnModel.getColumn(column).getWidth(), 0); 
        int height_wanted = (int) getPreferredSize().getHeight(); 
        addSize(table, row, column, height_wanted); 
        height_wanted = findTotalMaximumRowSize(table, row); 
        if (height_wanted != table.getRowHeight(row)) { 
            table.setRowHeight(row, height_wanted); 
        } 
        return this; 
    } 
 
    /** 
     * @param table  - JTable object 
     * @param row    - The row index of the cell being drawn. 
     * @param column - The column index of the cell being drawn. 
     * @param height - Row cell height as int value 
     *               This method will add size to cell based on row and column number 
     */ 
    private void addSize(JTable table, int row, int column, int height) { 
        Map<Object, Map<Object, Integer>> rowsMap = tablecellSizes.get(table); 
        if (rowsMap == null) { 
            tablecellSizes.put(table, rowsMap = new HashMap<Object, Map<Object, Integer>>()); 
        } 
        Map<Object, Integer> rowheightsMap = rowsMap.get(row); 
        if (rowheightsMap == null) { 
            rowsMap.put(row, rowheightsMap = new HashMap<Object, Integer>()); 
        } 
        rowheightsMap.put(column, height); 
    } 
 
    /** 
     * Look through all columns and get the renderer.  If it is 
     * also a TextAreaRenderer, we look at the maximum height in 
     * its hash table for this row. 
     * 
     * @param table -JTable object 
     * @param row   - The row index of the cell being drawn. 
     * @return row maximum height as integer value 
     */ 
    private int findTotalMaximumRowSize(JTable table, int row) { 
        int maximum_height = 0; 
        Enumeration<TableColumn> columns = table.getColumnModel().getColumns(); 
        while (columns.hasMoreElements()) { 
            TableColumn tc = columns.nextElement(); 
            TableCellRenderer cellRenderer = tc.getCellRenderer(); 
            if (cellRenderer instanceof TextAreaRenderer) { 
                TextAreaRenderer tar = (TextAreaRenderer) cellRenderer; 
                maximum_height = Math.max(maximum_height, 
                        tar.findMaximumRowSize(table, row)); 
            } 
        } 
        return maximum_height; 
    } 
 
    /** 
     * This will find the maximum row size 
     * 
     * @param table - JTable object 
     * @param row   - The row index of the cell being drawn. 
     * @return row maximum height as integer value 
     */ 
    private int findMaximumRowSize(JTable table, int row) { 
        Map<Object, Map<Object, Integer>> rows = tablecellSizes.get(table); 
        if (rows == null) return 0; 
        Map<Object, Integer> rowheights = rows.get(row); 
        if (rowheights == null) return 0; 
        int maximum_height = 0; 
        for (Map.Entry<Object, Integer> entry : rowheights.entrySet()) { 
            int cellHeight = entry.getValue(); 
            maximum_height = Math.max(maximum_height, cellHeight); 
        } 
        return maximum_height; 
    } 
}
I have tested with jdk1.4 to jdk1.5 in windows xp. Here is the tested code.

TextAreaRendererInTable.java


/** 
 * @(#)TextAreaRendererInTable.java 
 */ 
 
import javax.swing.*; 
import javax.swing.table.*; 
 
/** 
 * The standard class for testing the TextAreaRenderer class. 
 * This class inherits from JFrame, a standard component class. 
 * 
 * @author Manivel 
 * @see JFrame 
 */ 
public class TextAreaRendererInTable extends JFrame { 
 
    /** 
     * Creates a TextAreaRendererInTable object. 
     */ 
    public TextAreaRendererInTable() { 
    } 
 
    /** 
     * This method build the table. 
     */ 
    private void showTable() { 
        JTable table = new JTable(5, 3); 
 
        TableColumnModel cmodel = table.getColumnModel(); 
        TextAreaRenderer textAreaRenderer = new TextAreaRenderer(); 
 
        cmodel.getColumn(0).setCellRenderer(new DefaultTableCellRenderer()); 
        cmodel.getColumn(1).setCellRenderer(textAreaRenderer); 
        cmodel.getColumn(2).setCellRenderer(textAreaRenderer); 
 
        addRows(table); 
 
        getContentPane().add(new JScrollPane(table)); 
        setSize(500, 400); 
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        setLocationRelativeTo(null); 
        setTitle("Text Area Renderer In Table"); 
        setVisible(true); 
 
    } 
 
    /** 
     * This method will add rows into table. 
     * 
     * @param table - JTable object 
     */ 
    private void addRows(JTable table) { 
        String props = "Joy is not in things but in us"; 
        for (int i = 0; i < 5; i++) { 
            table.setValueAt(props + "-" + props, i, 0); 
            table.setValueAt(props, i, 1); 
            table.setValueAt(props + "-" + props + "-" + props, i, 2); 
        } 
    } 
 
    /** 
     * Main method of TextAreaRendererInTable class 
     * 
     * @param args - Defualt main method string args 
     */ 
    public static void main(String[] args) { 
        new TextAreaRendererInTable().showTable(); 
    } 
} 

 

That's it!!

Copyright - There is no copyright on the code. You can copy, change and distribute it freely. Just mentioning this site should be fair

(C) August 2008, manivelcode

3 comments:

Saudagar said...

Thanks buddy...
good work..........

Unknown said...

I tested this method, and as long as the table with all entries is assembled before it is actually displayed, everything works fine. But when I add new entries to my table while it is showing, the new entries do not show, and the program gets hooked up in an endless loop, going through the process of resetting the rowHeight again and again, but never succeeding.

Unknown said...

I love you, this is great