Running on Java 24-ea+24-2960 (Preview)
Home of The JavaSpecialists' Newsletter

045Multi-Line Cells in the JTable

Author: Dr. Heinz M. KabutzDate: 2002-04-11Java Version: 1.3Category: GUI
 

Abstract: In this newsletter we have a look at how we can render a JTextArea in a JTable cell.

 

Welcome to the 45th edition of The Java(tm) Specialists' Newsletter, read in over 78 countries, with newest additions Thailand and Iceland. Both end with "land" but they couldn't be two more opposite countries. Why don't those drivers who insist on crawling along the German Autobahn at 140km/h stick to the slow lane? I drove almost 500km on Friday, and had the opportunity to meet Carl Smotricz (my archive keeper) and some other subscribers in Frankfurt. We had some very inspiring discussions regarding Java performance, enjoyed some laughs at Java's expense and listened to my tales of life in South Africa.

Unsubscription Fees: Some of my readers wrote to tell me what a fantastic idea unsubscription fees were to make some money. Others wrote angry notes asking how I had obtained their credit card details. All of them were wrong! Note the date of our last newsletter - 1st April! Yes, it was all part of the April Fool's craze that hits the world once a year. Apologies to those of you who found that joke in poor taste (my wife said I shouldn't put it in, but I didn't listen to her). The rest of the newsletter was quite genuine. A friend, who was caught "hook, line & sinker", suggested that I should clear things up and tell you exactly what my purpose is in publishing "The Java(tm) Specialists' Newsletter":

#1. Publishing this newsletter is my hobby: No idealism here at all. A friend encouraged me a few years ago to write down all the things I had been telling him about Java, so one day I simply started, and I have carried on doing it. It's a great way to relax, put the feet up and think a while.

#2. There are no subscription / unsubscription fees: The day that I'm so broke that I need to charge you for reading the things I write, will be the day that I immediately start looking for work as a permanent employee again. There are neither subscription nor unsubscription fees, nor will there ever be.

#3. How do I earn my living? Certainly not by writing newsletters! I spend about 75% of my time writing Java code on contract for customers situated in various parts of the world. 20% of my time is spent presenting Java and Design Patterns courses in interesting places such as Mauritius and South Africa and the last 5% is spent advising companies about Java technology.

#4. Marketing for Maximum Solutions: Because people know my company and me through this newsletter, I have received many requests for courses, contract work and consulting, and this helps me to make a living. My hobby of writing the newsletter has turned out to have some nice side effects.

And now, without wasting any more time, let's look at a real-life Java problem...

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Multi-Line Cells in the JTable

The last slide of all my courses says that my students may send me questions any time they get stuck. A few weeks ago Robert Crida from Peralex in Bergvliet, South Africa, who came on my Java course last year, asked me how to display a JTextArea within a cell of a JTable. I sensed it would take more than 5 minutes to answer and being in a rush to finish some work inbetween Mauritius and Germany, I told him it would take me a few days to get back to him. When I got to Germany, I promptly forgot about his problem, until one of his colleagues reminded me last week.

Robert was trying to embed a JTextArea object within a JTable. The behaviour that he was getting was that when he resized the width of the table, he could see that the text in the text area was being wrapped onto multiple lines but the cells did not become higher to show those lines. He wanted the table row height to be increased automatically to make the complete text area visible.

He implemented a JTextArea cell renderer as below:

import java.awt.Component;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.table.TableCellRenderer;

public class TextAreaRenderer extends JTextArea
    implements TableCellRenderer {

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

  public Component getTableCellRendererComponent(JTable jTable,
      Object obj, boolean isSelected, boolean hasFocus, int row,
      int column) {
    setText((String)obj);
    return this;
  }
}

I wrote some test code to try this out. Before I continue, I need to point out that I use the SUN JDK 1.3.1 whereas Robert uses the SUN JDK 1.4.0. The classic "write once, debug everywhere" is a topic for another newsletter ...

import javax.swing.*;
import java.awt.BorderLayout;

public class TextAreaRendererTest extends JFrame {
  // The table has 10 rows and 3 columns
  private final JTable table = new JTable(10, 3);

  public TextAreaRendererTest() {
    // We use our cell renderer for the third column
    table.getColumnModel().getColumn(2).setCellRenderer(
      new TextAreaRenderer());
    // We hard-code the height of rows 0 and 5 to be 100
    table.setRowHeight(0, 100);
    table.setRowHeight(5, 100);
    // We put the table into a scrollpane and into a frame
    getContentPane().add(new JScrollPane(table));
    // We then set a few of the cells to our long example text
    String test = "The lazy dog jumped over the quick brown fox";
    table.getModel().setValueAt(test, 0, 0);
    table.getModel().setValueAt(test, 0, 1);
    table.getModel().setValueAt(test, 0, 2);
    table.getModel().setValueAt(test, 4, 0);
    table.getModel().setValueAt(test, 4, 1);
    table.getModel().setValueAt(test, 4, 2);
  }

  public static void main(String[] args) {
    TextAreaRendererTest test = new TextAreaRendererTest();
    test.setSize(600, 600);
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    test.show();
  }
}

You'll notice when you run this, that when the row is high enough the text wraps very nicely inside the JTextArea, as in cell (0, 2). However, the JTable does not increase the row height in cell (4, 2) just because you decide to put a tall component into the cell. It requires a bit of prodding to do that.

My first approach was to override getPreferredSize() in the TextAreaRenderer class. However, that didn't work because JTable didn't take your preferred size into account in sizing the rows. I spent about an hour delving through the source code of JTable and JTextArea. After a lot of experimentation, I found out that JTextArea actually had the correct preferred size according to the width of the column in the JTable. I tried changing the getTableCellRendererComponent() method:

  public Component getTableCellRendererComponent(JTable jTable,
      Object obj, boolean isSelected, boolean hasFocus, int row,
      int column) {
    setText((String)obj);
    table.setRowHeight(row, (int)getPreferredSize().getHeight());
    return this;
  }

On first glimpse, the program seemed to work correctly now, except that my poor CPU was running at 100%. The problem was that when you set the row height, the table was invalidated and that caused getTableCellRendererComponent() to be called in order to render all the cells again. This in turn then set the row height, which invalidated the table again. In order to put a stop to this cycle of invalidation, I needed to check whether the row is already the correct height before setting it:

  public Component getTableCellRendererComponent(JTable jTable,
      Object obj, boolean isSelected, boolean hasFocus, int row,
      int column) {
    setText((String)obj);
    int height_wanted = (int)getPreferredSize().getHeight();
    if (height_wanted != table.getRowHeight(row))
      table.setRowHeight(row, height_wanted);
    return this;
  }

I tried it out (on SUN JDK 1.3.1) and it worked perfectly. There are some restrictions with my solution:

  1. It will only work when only one column contains the TextAreaRenderer. You can easily write around this problem by having coordination between the various TextAreaRenderers.
  2. You need to implement a TextAreaEditor, which I imagine will actually be a lot easier.

Satisfied, I sent off the answer to Robert, with the words: "After spending an hour tearing out my hair, I found a solution for you, it's so simple you'll kick yourself, like I did myself ;-)"

A few hours the answer came back: "Your solution does not solve my problem at all."

"What?" I thought. Upon questioning his configuration, we realised that I was using JDK 1.3.1 and Robert was using JDK 1.4.0. I tried it on JDK 1.4.0 on my machine, and truly, it did not render properly! What had they changed so that it didn't work anymore? After battling for another hour trying to figure out what the difference was and why it didn't work out, I gave up and carried on with my other work of tuning someone's application server. If you know how to do it in JDK 1.4.0, please tell me!

I have avoided JDK 1.4 for real-life projects, because I prefer others to find the bugs first. Most of my work is spent programming on real-life projects, so JDK 1.3.1 is the version I'm stuck with. My suspicion of new JDK versions goes back to when I started using JDK 1.0.x, JDK 1.1.x, JDK 1.2.x. I found that for every bug that was fixed in a new major version, 3 more appeared, and I grew tired of being a guinea pig. I must admit that I'm very happy with JDK 1.3.1, as I was with JDK 1.2.2 and JDK 1.1.8. I think that once JDK 1.4.1 is released I'll start using it and then you'll see more newsletters about that version of Java.

In a future newsletter I will demonstrate how you can implement "friends" at runtime in the JDK 1.4.

Heinz

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '23 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...