Below is some sample code that I am having some issues with. I have a
simple JTable with 2 simple custom cell renderers. When the JTable is
being redrawn or repainted or whatever...it "jumps". Seems to happen
the most right after scrolling. Does anyone know why or what I can do
to stop it from doing it?
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableTest extends JPanel {
public TableTest() {
this.setLayout(new BorderLayout());
// create some columns
Vector columns = new Vector();
columns.add("Column A");
columns.add("Column B");
columns.add("HTML");
columns.add("Column D");
columns.add("Multiline");
// create the data
Vector data = createFakeData();
// create the JTable
JTable table = new JTable(data, columns);
// set the HTML renderer
TableColumn col = table.getColumnModel().getColumn(2);
col.setCellRenderer(new HtmlCellRenderer());
// set the Multiline renderer
TableColumn col2 = table.getColumnModel().getColumn(4);
col2.setCellRenderer(new MultiLineCellRenderer());
JScrollPane jsp = new JScrollPane(table);
this.add(jsp);
}
public Vector createFakeData() {
// create some fake data
Vector data = new Vector();
for (int i = 0; i < 10; i++) {
Vector temp = new Vector();
temp.add(new String("[" + i + ", 1]"));
temp.add(new String("[" + i + ", 2]"));
temp.add(new String("<b>test</b><br><i>data</i>"));
temp.add(new String("[" + i + ", 3]"));
temp.add(new String("1\n2\n3\n"));
data.add(temp);
}
Vector oneMoreRow = new Vector();
oneMoreRow.add(new String("[10, 1]"));
oneMoreRow.add(new String("[10, 2]"));
oneMoreRow.add(new String("more <i>data</i>"));
oneMoreRow.add(new String("[10, 3]"));
oneMoreRow.add(new String("1"));
data.add(oneMoreRow);
for (int i = 11; i < 21; i++) {
Vector temp = new Vector();
temp.add(new String("[" + i + ", 1]"));
temp.add(new String("[" + i + ", 2]"));
temp.add(new String("<b>blah</b><br><i>data</i>"));
temp.add(new String("[" + i + ", 3]"));
temp.add(new String("1\n2\n"));
data.add(temp);
}
return data;
}
public static void main(String args[]) {
JFrame f = new JFrame();
f.getContentPane().add(new TableTest());
f.pack();
f.show();
}
}
class HtmlCellRenderer extends AbstractCellEditor implements
TableCellRenderer {
private JLabel label = new JLabel();
private String value = "";
public HtmlCellRenderer() {
this.label.setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int
column) {
this.value = value.toString();
this.label.setText("<html><body>" + this.value +
"</body></html>");
if (isSelected) {
// do something here like change the color
this.label.setForeground(Color.red);
this.label.setBackground( table.getBackground() ) ;
} else {
this.label.setForeground( table.getForeground() ) ;
this.label.setBackground( table.getBackground() ) ;
}
if (hasFocus) {
this.label.setBorder(UIManager.getBorder(
"Table.focusCellHighlightBorder"));
if (table.isCellEditable(row, column)) {
this.label.setForeground(UIManager.getColor("Table.focusCellForeground"));
this.label.setBackground(UIManager.getColor("Table.focusCellBackground"));
}
} else {
this.label.setBorder( new EmptyBorder( 1, 2, 1, 2 ) ) ;
}
return this.label;
}
public Object getCellEditorValue() {
return this.value;
}
}
class MultiLineCellRenderer extends JTextArea implements
TableCellRenderer {
public MultiLineCellRenderer() {
setLineWrap(true);
setWrapStyleWord(true);
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int
column) {
int height_wanted = (int)getPreferredSize().getHeight();
if (height_wanted != table.getRowHeight(row)) {
table.setRowHeight(row, height_wanted);
}
setText((value == null) ? "" : value.toString());
return this;
}
}
Roedy Green - 28 Jun 2004 16:54 GMT
> temp.add(new String("[" + i + ", 1]"));
there is no need for the new String. The contents of the () are
already a String. This however, is not what is causing the jumping,
just making gc more frequent.

Signature
Canadian Mind Products, Roedy Green.
Coaching, problem solving, economical contract programming.
See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.
Roedy Green - 28 Jun 2004 16:58 GMT
>Does anyone know why or what I can do
>to stop it from doing it?
I'd check out the usual cell rendering and Swing gotchas.
See http://mindprod.com/jgloss/gotchas.html#TABLECELLRENDERER
You must be very careful with Swing to do calculation NOT on the Swing
thread so you don't block it, and do all painting stuff with
invokeLater so that it happens on the Swing thread.
See http://mindprod.com/jgloss/swing.html for details.

Signature
Canadian Mind Products, Roedy Green.
Coaching, problem solving, economical contract programming.
See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.
Thomas Fritsch - 28 Jun 2004 18:48 GMT
>...
>
[quoted text clipped - 12 lines]
> boolean hasFocus,
> int row, int column) {
setText((value == null) ? "" : value.toString());
> int height_wanted = (int)getPreferredSize().getHeight();
>
> if (height_wanted != table.getRowHeight(row)) {
> table.setRowHeight(row, height_wanted);
> }
>
//
> // setText((value == null) ? "" : value.toString());
>
> return this;
> }
>}
>
Your MultiLineCellRenderer seems to be on the edge of legality (or even
beyond ;-) ). Changing a row height from within
the Swing thread is very dangerous.
Anyway: I have played around with its getTableCellRendererComponent
method. Writing the "setText"-line at the beginning instead of at the
end (see code above) prevents the table from "jumping", at least in my
Java1.3 environment.
But I think this bugfix is more a hack than a solution.

Signature
Thomas<dot>Fritsch<squiggle>ops<dot>de