JTable Wordwrap
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 4 of 4

Thread: JTable Wordwrap

  1. #1
    Join Date
    Apr 2009
    Posts
    47

    JTable Wordwrap

    I am having trouble implementing a custom cell renderer which will wrap message content when it extends past one line in length. The following is what I have:

    Code:
    public class MessageTable extends JTable
    {
    	private static MessageTable messageTable;
    	private DefaultTableModel model = new DefaultTableModel();
    	private String[] emptyData = {};
    	private TreeMap<Integer, String> messages = null;
    	
    	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);      
                    
                    this.setBackground(Color.YELLOW);
                    
                    int fontHeight = this.getFontMetrics(this.getFont()).getHeight();
                    int textLength = this.getText().length();
                    int lines = textLength / this.getColumns() +1;//+1, because we need at least 1 row.                       
                    int height = fontHeight * lines;                        
                    table.setRowHeight(row, height);
                    return this;
            }
    	}
    
    	public MessageTable()
    	{
    		super();
    		messageTable = this;
    		this.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);		
    		
    		model.addColumn("Message Number", emptyData);
    		model.addColumn("Message Content", emptyData);
    		
    		this.setModel(model);
    		this.setFont(MappingView.theFont);
    		
    		this.setDefaultRenderer(String.class, new LineWrapCellRenderer());
    	}
    
    	/**
    	 * Set the current messages.
    	 * @param messages
    	 */
    	public void setCurrentMessages(TreeMap<Integer, String> messages)
    	{
    		clearCurrentMessages();
    
    		this.messages = messages;
    
    		if (messages != null)
    		{
    			for (Integer key : messages.keySet())
    			{
    				String[] row = { key.toString(), messages.get(key).toString() };
    				model.addRow(row);
    			}
    		}
    	}
    What am I doing wrong here?

    Thanks.

  2. #2
    dlorde is offline Elite Member Power Poster
    Join Date
    Aug 1999
    Location
    UK
    Posts
    10,163

    Re: JTable Wordwrap

    The default column class is Object.class, so your String.class renderer doesn't get called. You need to set the default renderer for Object.class, not String.class.

    If you want to have specific class types for your columns, you need to override getColumnClass(..) in the TableModel. This isn't usually necessary, because you can set the renderer however you like for each column in the getTableCellRendererComponent method.

    If you want to dynamically adjust the row height to accommodate your wrapped text, you need to allow for resizing of the table column widths, so that your row height is always sufficient to display the number of lines in the cell with the most. Something like this:
    Code:
    public class LineWrapCellRenderer extends JTextArea implements TableCellRenderer {
    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)
    {
        setText((String) value);
        setWrapStyleWord(true);
        setLineWrap(true);
        setBackground(Color.YELLOW);
    
        // see next post for better way to do this
        FontMetrics fm = getFontMetrics(this.getFont());
        int fontHeight = fm.getHeight() + table.getRowMargin();
        int textLength = fm.stringWidth(getText());  // length in pixels
        int colWidth = table.getColumnModel().getColumn(column).getWidth();
        int lines = textLength / colWidth +1; // +1, because we need at least 1 row.
        int height = fontHeight * lines;
    
        // ensure the row height fits the cell with most lines
        if (column == 0 || height > rowHeight) {
            table.setRowHeight(row, height);
            rowHeight = height;
        }
        return this;
    }
    There's probably an easier way of doing this, but it works reasonably well. [E.T.A See post below for improvement]

    Incidentally, you don't have to prefix every member variable with 'this'. It's only necessary if there's some clash or possible confusion.

    I'm also curious to know why you have a private static member variable of the class instance itself - it means that every instance of the class shares a reference to the most recent instance, which probably isn't what you wanted.

    Computer Science is a science of abstraction -creating the right model for a problem and devising the appropriate mechanizable techniques to solve it...
    A. Aho and J. Ullman
    Last edited by dlorde; April 15th, 2011 at 10:07 AM.
    Please use &#91;CODE]...your code here...&#91;/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.

  3. #3
    dlorde is offline Elite Member Power Poster
    Join Date
    Aug 1999
    Location
    UK
    Posts
    10,163

    Re: JTable Wordwrap

    Update: I thought there was a better way of working out what the row height should be, and there is - you can do it without messing with font metrics by getting the JTextArea to do it for you. If you set the width, it will calculate its preferred size for that width:
    Code:
    // 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();
    Don't worry about people stealing your ideas. If your ideas are any good, you'll have to ram them down people's throats...
    H. Aiken
    Please use &#91;CODE]...your code here...&#91;/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.

  4. #4
    Join Date
    Oct 2011
    Posts
    1

    Re: JTable Wordwrap

    Thanks dlorde

    This was exactly what I was looking for. Eveything else on the web had similar solutions, but none of them seemed complete.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center