Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[SWING] Zeitpunkt, um eigenen TableCellRenderer zu setzen?

0 views
Skip to first unread message

Marco Schmidt

unread,
Dec 14, 2003, 10:08:04 AM12/14/03
to
Im Konstruktor einer von JFrame abgeleiteten Klasse wird u.a. auch
eine JTable table eingefügt. Am Ende des Konstruktors wird dann ein
eigener TableCellRenderer für eine Spalte dieser Tabelle gesetzt:

table.getColumnModel().getColumn(4).setCellRenderer(new MyRenderer());

Nun führte das, nachdem Eclipse ein paar Stunden nicht benutzt wurde,
beim Start des Programms zu folgendem Fehler:

java.lang.ArrayIndexOutOfBoundsException: 4 >= 0
at java.util.Vector.elementAt(Vector.java:431)
at
javax.swing.table.DefaultTableColumnModel.getColumn(DefaultTableColumnModel.java:277)
at gui.MyFrame.<init>(MyFrame.java:79)
at gui.MyFrame.main(MyFrame.java:145)
Exception in thread "main"

Eine TableColumn #4 scheint also noch nicht zu existieren (genauer
gesagt: gar keine TableColumn existierte zu dem Zeitpunkt, da der
Vector mit den TableColumn-Objekten leer war).

Starte ich das Programm danach mehrmals neu, funktioniert es jedes Mal
und der Renderer malt auch wie er soll. Ich vermute, daß das Laden /
Initialisieren der Tabelle im Hintergrund noch nicht fertig war (evtl.
weil vieles aus rt.jar neugeladen werden mußte weil es nicht mehr im
Dateisystemcache war, wie gesagt, Start aus Eclipse heraus nach
einigen Stunden "Ruhe"), als versucht wurde, den Renderer zu setzen.

Wie sollte ich vorgehen, um das Problem zu vermeiden? Wann oder wo
sollte der Renderer gesetzt werden bzw. wie kann ich erzwingen, daß
die Tabelle fertiggestellt wird, bevor ich sie manipuliere? Natürlich
kann ich in einer Schleife warten, bis es fünf Spalten gibt, aber
vielleicht geht's auch anders. Außerdem interessiert es mich
grundsätzlich, an welchen Stellen der Konstruktion von GUIs man mit
solchen Synchronisationsproblemen rechnen muß.

Gruß,
Marco
--
Bitte nur in der Newsgroup antworten, nicht per Email!
de.comp.lang.java Homepage: http://www.dclj.de/
FAQ: http://www.faqs.org/faqs/de/comp-lang-java/faq/
Meine Java-Seiten: http://www.geocities.com/marcoschmidt.geo/java.html

Aljoscha Rittner

unread,
Dec 14, 2003, 2:20:01 PM12/14/03
to
Marco Schmidt schrieb:

> Im Konstruktor einer von JFrame abgeleiteten Klasse wird u.a. auch
> eine JTable table eingefügt. Am Ende des Konstruktors wird dann ein
> eigener TableCellRenderer für eine Spalte dieser Tabelle gesetzt:
>
> table.getColumnModel().getColumn(4).setCellRenderer(new MyRenderer());

Das sieht aber böse aus. Grundsätzlich würde ich nicht empfehlen einen
Renderer abhängig einer Spaltenposition zu setzen. Ein Renderer ist
etwas zur Darstellung eines Wertes abhängig von seinem Typ. Wert und
Typ findet sich im TableModel. JTable unterstützt zumindest das
Verhalten bei Datentypen (Class) einen spezialisierten Renderer zu
verwenden. Vielleicht ist es bei deinem Design schon ausreichend einen
DefaultRenderer zum Klassen-Typ zu setzen.

> Nun führte das, nachdem Eclipse ein paar Stunden nicht benutzt wurde,
> beim Start des Programms zu folgendem Fehler:

LOL. Erste Ausrede eines Anwenders: Ich habe nichts gemacht!

> java.lang.ArrayIndexOutOfBoundsException: 4 >= 0
> at java.util.Vector.elementAt(Vector.java:431)
> at
> javax.swing.table.DefaultTableColumnModel.getColumn(DefaultTableColumnModel.java:277)
> at gui.MyFrame.<init>(MyFrame.java:79)
> at gui.MyFrame.main(MyFrame.java:145)
> Exception in thread "main"
>
> Eine TableColumn #4 scheint also noch nicht zu existieren (genauer
> gesagt: gar keine TableColumn existierte zu dem Zeitpunkt, da der
> Vector mit den TableColumn-Objekten leer war).
>
> Starte ich das Programm danach mehrmals neu, funktioniert es jedes Mal
> und der Renderer malt auch wie er soll. Ich vermute, daß das Laden /
> Initialisieren der Tabelle im Hintergrund noch nicht fertig war (evtl.
> weil vieles aus rt.jar neugeladen werden mußte weil es nicht mehr im
> Dateisystemcache war, wie gesagt, Start aus Eclipse heraus nach
> einigen Stunden "Ruhe"), als versucht wurde, den Renderer zu setzen.

Cache-Überlegungen würde ich mal außen vorlassen. Du hast aber
sicherlich ein Thread-Problem. Das kann zB. allein schon passieren,
wenn du new JFrame().show() aufrufst. Da laufen schon 2 Threads die
nur damit beschäftigt sind, das JFrame zu initialisieren. Der
EventDispatcher-Thread und der Main-Thread. Das führt gerne mal zu
Problemen.

> Wie sollte ich vorgehen, um das Problem zu vermeiden? Wann oder wo
> sollte der Renderer gesetzt werden bzw. wie kann ich erzwingen, daß
> die Tabelle fertiggestellt wird, bevor ich sie manipuliere?

Wenn du das Setzen der Renderer explizit vom Modell abhängig machen
willst, solltest du evtl erwägen dein JTable zu erweitern (weil eine
feste Verknüpfung zwischen View und Model erfolgt):

public class SpecialModelTable extends JTable {
...

Dann eine Methode für die Renderer:

List defaultRenderer = new ArrayList ();

public setDefaultRenderer (int column, TableCellRenderer tc) {
while ( (defaultRenderer.size()-1) < column ) {
defaultRenderer.add (null);
}
defaultRenderer.set (column, tc);
}

und nun setModel überschreiben:

public void setModel (TableModel tm) {
removeMyDefaultRenderer (); // wenn notwendig, implementieren
super.setModel (tm);
for ( int i = 0; i < defaultRenderer.size(); i++ ) {
TableCellRenderer tcr =
(TableCellRenderer)defaultRenderer.get(i);
if ( tcr != null ) {
getColumnModel().getColumn(i)
.setCellRenderer(tcr);
}
}
}

...
}

Es gibt natürlich auch andere Design-Ansätze und man muß noch einige
Dinge zusätzlich beachten, aber es ist nur ein Ideenansatz.

Gruß,
Josch.
--
... und ich haette da noch 600MB freien Festplattenspeicher auf CD
gebrannt,
natuerlich wenig benutzt und superschnell.
Daniel in goe.kleinanzeigen.allgemein

Marco Schmidt

unread,
Dec 15, 2003, 2:56:30 AM12/15/03
to
Aljoscha Rittner:

>> table.getColumnModel().getColumn(4).setCellRenderer(new MyRenderer());
>
>Das sieht aber böse aus.

He, das war das Ergebnis von 30 Minuten API-Docs-Recherche! :)

>Grundsätzlich würde ich nicht empfehlen einen
>Renderer abhängig einer Spaltenposition zu setzen. Ein Renderer ist
>etwas zur Darstellung eines Wertes abhängig von seinem Typ. Wert und
>Typ findet sich im TableModel. JTable unterstützt zumindest das
>Verhalten bei Datentypen (Class) einen spezialisierten Renderer zu
>verwenden. Vielleicht ist es bei deinem Design schon ausreichend einen
>DefaultRenderer zum Klassen-Typ zu setzen.

Die Besonderheit meines Renderers liegt darin, daß er gewisse Zellen
anders einfärbt. Das TableModel gibt in getValue für Spalte #4 ein
Objekt vom Typ MyClass zurück, das der Renderer auswertet, um über die
Farbe zu entscheiden.

Mit Deinen Tips (danke!) habe ich es nun so gelöst:

table.setDefaultRenderer(MyClass.class, new MyClassRenderer());

In meinem TableModel überschreibe ich getColumnClass und gebe für die
entsprechende Spalte MyClass.class zurück.

Klappt gut. Aber vielleicht sollte ich Eclipse wieder ein paar Stunden
alleinlassen, als ultimativen Test. :)

[...]

0 new messages