Home | JSP | EJB | JDBC | Java Servlets | WAP  | Free JSP Hosting  | Spring Framework | Web Services | BioInformatics | Java Server Faces | Jboss 3.0 tutorial | Hibernate 3.0 | XML
 
 
Hot Web Programming Job

 

Tutorial Categories: Ajax | Articles | JSP | Bioinformatics | Database | Free Books | Hibernate | J2EE | J2ME | Java | JavaScript | JDBC | JMS | Linux | MS Technology | PHP | RMI | Web-Services | Servlets | Struts | UML


 

Search Host

Monthly Fee($)
Disk Space (MB)
Register With us for Newsletter!
Visit Forum! Post Questions!
Jobs At RoseIndia.net!

Have tutorials?
Add your tutorial to our Java Resource and get tons of hits.

We offer free hosting for your tutorials. and exposure for thousands of readers. drop a mail
roseindia_net@yahoo.com
 
   

Tutorials

Java Server Pages

JAXB

Java Beans

JDBC

MySQL

Java Servlets

Struts

Bioinformatics

Java Code Examples

Interview Questions

 
Join For Newsletter

Powered by groups.yahoo.com
Visit Group! Post Questions!

Web Promotion

Web Submission

Submit Sites

Manual Submission?

Web Promotion Guide

Hosting Companies

Web Hosting Guide

Web Hosting

Linux

Beginner Guide to Linux Server

Frameworks

Persistence Framework

Web Frameworks

Free EAI Tools

Web Servers

Aspect Oriented Programming

Free Proxy Servers

Softwares

Adware & Spyware Remover

Open Source Softwares

JDK Tutorial - Multi-line cells in JTable in JDK 1.4+

       

This JDK Tutorial shows you  how to wrap text inside cells of a JTable.

2005-04-14 The Java Specialists' Newsletter [Issue 106] - Multi-line cells in JTable in JDK 1.4+

Author: Dr. Heinz M. Kabutz

JDK version: Sun JDKs 1.3.1_12, 1.4.2_05, 1.5.0_02

If you are reading this, and have not subscribed, please consider doing it now by going to our subscribe page. You can subscribe either via email or RSS.


Welcome to the 106th edition of The Java(tm) Specialists' Newsletter, sent to you from Vienna, Austria. The great staff at Alcatel booked me into a hotel that has free ADSL+WiFi access. This is still rather unusual in Europe, I am told. I am in Vienna, Austria, until the 22nd of April, so please let me know if you are available for a cup of coffee and chat after work. We had a great time last night at the Schweizerhaus, really experiencing Austrian hospitality and atmosphere at its best.

On the first day of the courses, we noticed that the projector was playing up, changing colours intermittently. Changing the projector did not help, so we traced the problem to my Dell D800 heavyweight notebook. I phoned DELL Austria at about 15:00 on Tuesday, and by 14:00 on Wednesday someone had arrived at Alcatel and had swopped out my motherboard. No charge at all! Super service, thanks DELL!

We are running a Java Course in Cape Town in May, so please let me know if you or your developers would like to attend. In addition, 2005 is the year where I intend focusing on Java in Europe, so please write to me if you would benefit from some training or consulting or programming.

Multi-line cells in JTable in JDK 1.4+

Three years ago, I played an April Fools' joke on my readers, as is customary in South Africa. However, with 109 countries on the subscription list, I have stopped playing the fool, since this is can cause confusion in cultures that do not celebrate the 1st of April. In a follow-up newsletter, I explained that the unsubscription fees were nothing but a joke.

Coincidentally, almost three years ago to the day, I wrote about Multi-line cells in the JTable. I discussed how to wrap text inside cells of a JTable. My solution only worked pre-JDK 1.4 , so I asked readers to send me a solution if they found it.

Since I wrote that letter, several readers have sent solutions that worked for JDK 1.4 and JDK 5.0: Scott Sauyet, Dave Combs, Hitesh Patel, Debbie Utley, Wolf Siberski, Dirk Hillbrecht, Andrew Cole and Sami. Thank you very much!

Most of the solutions consisted of adding one line to my code:


    setSize(columnModel.getColumn(column).getWidth(), 100000);
  

This magically made the renderer work under JDK 1.4 and 1.5. However, it did not address the other issues that I mentioned in the original newsletter:

  1. It worked when only one column contained the TextAreaRenderer.
  2. I did not implement a TextAreaEditor.

Something else which bothered me with the proposed solutions was that the cells with our renderers looked slightly different to the cells with default renderers.

Here is a renderer followed by an editor that address all these issues:

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.util.*;

public class TextAreaRenderer extends JTextArea
    implements TableCellRenderer {
  private final DefaultTableCellRenderer adaptee =
      new DefaultTableCellRenderer();
  /** map from table to map of rows to map of column heights */
  private final Map cellSizes = new HashMap();

  public TextAreaRenderer() {
    setLineWrap(true);
    setWrapStyleWord(true);
  }

  public Component getTableCellRendererComponent(//
      JTable table, Object obj, boolean isSelected,
      boolean hasFocus, int row, int column) {
    // set the colours, etc. using the standard for that platform
    adaptee.getTableCellRendererComponent(table, obj,
        isSelected, hasFocus, row, column);
    setForeground(adaptee.getForeground());
    setBackground(adaptee.getBackground());
    setBorder(adaptee.getBorder());
    setFont(adaptee.getFont());
    setText(adaptee.getText());

    // This line was very important to get it working with JDK1.4
    TableColumnModel columnModel = table.getColumnModel();
    setSize(columnModel.getColumn(column).getWidth(), 100000);
    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;
  }

  private void addSize(JTable table, int row, int column,
                       int height) {
    Map rows = (Map) cellSizes.get(table);
    if (rows == null) {
      cellSizes.put(table, rows = new HashMap());
    }
    Map rowheights = (Map) rows.get(new Integer(row));
    if (rowheights == null) {
      rows.put(new Integer(row), rowheights = new HashMap());
    }
    rowheights.put(new Integer(column), new Integer(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.
   */
  private int findTotalMaximumRowSize(JTable table, int row) {
    int maximum_height = 0;
    Enumeration columns = table.getColumnModel().getColumns();
    while (columns.hasMoreElements()) {
      TableColumn tc = (TableColumn) 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;
  }

  private int findMaximumRowSize(JTable table, int row) {
    Map rows = (Map) cellSizes.get(table);
    if (rows == null) return 0;
    Map rowheights = (Map) rows.get(new Integer(row));
    if (rowheights == null) return 0;
    int maximum_height = 0;
    for (Iterator it = rowheights.entrySet().iterator();
         it.hasNext();) {
      Map.Entry entry = (Map.Entry) it.next();
      int cellHeight = ((Integer) entry.getValue()).intValue();
      maximum_height = Math.max(maximum_height, cellHeight);
    }
    return maximum_height;
  }
}
  

I know that the mechanism for handling the cell renderer for several columns is rather complex and inefficient. However, it caters for the general case where one instance of the cell renderer is used for several columns, or even for several tables.

You will notice that I am borrowing the formatting of the DefaultTableCellRenderer, so that the Text Area looks the same as the other cells, for the particular platform and JVM version.

As predicted in my newsletter three years ago, it was a "Kinderspiel" (child's play) to write the TextAreaEditor. A few points to note: I subclass the DefaultCellEditor, which only caters for JTextField, JComboBox and JCheckbox as editors. I therefore replace the editorComponent with my own, and also set my own delegate. In order to make it possible to edit more than the current cell allows, I put the TextArea for editing into a JScrollPane, and I set its border to null, to prevent it from showing the scrollbar unnecessarily.

import javax.swing.*;

public class TextAreaEditor extends DefaultCellEditor {
  public TextAreaEditor() {
    super(new JTextField());
    final JTextArea textArea = new JTextArea();
    textArea.setWrapStyleWord(true);
    textArea.setLineWrap(true);
    JScrollPane scrollPane = new JScrollPane(textArea);
    scrollPane.setBorder(null);
    editorComponent = scrollPane;

    delegate = new DefaultCellEditor.EditorDelegate() {
      public void setValue(Object value) {
        textArea.setText((value != null) ? value.toString() : "");
      }
      public Object getCellEditorValue() {
        return textArea.getText();
      }
    };
  }
}
  

I tested this on JDK 1.3.1 right up to JDK 1.5.0, under the Windows, Motif and Metal Look and Feels, and it appears the same as a normal JTable cell. Here is some test code:

import javax.swing.*;
import javax.swing.table.*;

public class TextAreaRendererTest extends JFrame {
  private final JTable table = new JTable(10, 4);

  public TextAreaRendererTest() {
    super(System.getProperty("java.vm.version"));

    // We use our cell renderer for columns 1, 2, 3
    TableColumnModel cmodel = table.getColumnModel();
    TextAreaRenderer textAreaRenderer = new TextAreaRenderer();

    cmodel.getColumn(1).setCellRenderer(textAreaRenderer);
    cmodel.getColumn(2).setCellRenderer(new TextAreaRenderer());
    // I am demonstrating that you can have several renderers in
    // one table, and they communicate with one another in
    // deciding the row height.
    cmodel.getColumn(3).setCellRenderer(textAreaRenderer);
    TextAreaEditor textEditor = new TextAreaEditor();
    cmodel.getColumn(1).setCellEditor(textEditor);
    cmodel.getColumn(2).setCellEditor(textEditor);
    cmodel.getColumn(3).setCellEditor(textEditor);

    String test = "The lazy dog jumps over the quick brown fox";

    for (int column = 0; column < 4; column++) {
      table.setValueAt(test, 0, column);
      table.setValueAt(test, 4, column);
    }
    test = test + test + test + test + test + test + test + test;
    table.setValueAt(test, 4, 2);

    getContentPane().add(new JScrollPane(table));
    setSize(600, 600);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
  }
  public static void main(String[] args) {
    new TextAreaRendererTest();
  }
}
  

Well, it is late, and I need to hit the sack so that I can be fresh tomorrow for the Design Patterns Course at Alcatel Austria :)

Don't forget to let me know if you are currently in Austria!

Kind regards

Heinz

This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

       

Useful Links
  JDO Tutorials
  EAI Articles
  Struts Tutorials
  Java Tutorials
  Java Certification

Tell A Friend
Your Friend Name
Search Tutorials

 

 
 
Browse all Java Tutorials
Java JSP Struts Servlets Hibernate XML
Ajax JDBC EJB MySQL JavaScript JSF
Maven2 Tutorial JEE5 Tutorial Java Threading Tutorial Photoshop Tutorials Linux Technology
Technology Revolutions Eclipse Spring Tutorial Bioinformatics Tutorials Tools SQL
 

Home | JSP | EJB | JDBC | Java Servlets | WAP  | Free JSP Hosting  | Search Engine | News Archive | Jboss 3.0 tutorial | Free Linux CD's | Forum | Blogs

About Us | Advertising On RoseIndia.net

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2007. All rights reserved.