# JTable für sehr viele Daten sehr langsam



## redbomber (20. Mrz 2009)

Hi zusammen,

ich habe mal wieder ein Problem und leider sehr ratlos.

Beim Scrollen (durch klick auf Pfeil) wird meine Table sehr sehr langsam neu gezeichnet, 
die scrollbar zuckelt wirklich nur millimeter für millimeter runter. 
Und ich bin schon langer auf der Suche woran dies liegt.

Meine Table
Es geht um eine JTable. Diese JTable erbt von JPanel. 
Jede Zelle wird bei mir farblich dargestell durch setBackground(Color.xx).

Ich besitze ein eigenes TableModel, welches von AbstractTableModel erbt.
Dieses Model besitzt die Methode getValueAt() --> Dies bedeutet also, dass nur aus den Zellen 
die Daten geholt werden, welche benötigt werden. Dies sind nur alle DARGESTELLTEN Zellen.

Meine Daten:
mein Table Model kann entweder auf eine TreeMap<LinkedList<Objekte> > zugreifen,
oder auf eine ArrayList<LinkedList<Objekte> >
Diese Daten sind SEHR GROß, die ArrayList ist zb. 200000 Felder lang.

Zoom:
Ich kann die Einträge der TreeMap bzw. ArrayList zusammenfassen.
Also z.B.: Eintrag 1-10 in ArrayList wird in Zelle 1 der Tabelle dargestellt.
Eintrag 11-20 der ArrayList wird in Zelle 2 der Tabelle dargestellt.
usw. (entsprechend für TreeMap).

Auf ZoomStufe 1 befindet sich Eintrag in der TreeMap bzw. ArrayList in einer Zelle in der Tabelle.
Ebenso ist hier die LinkedList<Objekte> meist nur mit einem Objekt befüllt.

Wird also bei Zoom 10 die Tabelle gezeichnet, dann werden die LinkedList<Objekte> von 10 Zellen immer 
in eine zusammengefasst. und durch die getValueAt() Methode zurückgegeben.

Bei großem Zoom würde ich also erwarten, dass die Darstellung der Tabelle langsamer wird, da zuerst die
LinkedList<Objekte> von der verschiedenen Zellen zusammengefasst werden.
Aber selbst bei Zoom 1 ist das ganze wahnsinnig langsam. Auf dem Bildschirm sin dann etwa 1000 Zellen 
dargestellt.

Wo kann der Fehler liegen? Feuere ich zuviele Events, wodurch die Tabelle zu oft gezeichnet wird?
Liegt das Problem an meiner Datenstruktur, auf die ich über das TableModel zugreife?
Wie kann ich es testen wo genau sehr viel Zeit verloren geht?


----------



## Wildcard (20. Mrz 2009)

> Es geht um eine JTable. Diese JTable erbt von JPanel.


Na wohl kaum, sonst wäre es wohl keine JTable...
Kann zB am Renderer, oder an getValue liegen, aber bevor man lange rätselt, verwende einen Profiler.


----------



## Gast2 (21. Mrz 2009)

Moin,

das liegt an Windows (ich gehe jetzt davon aus das Du auch Windows verwendest) ... bei mir werden ca. 110000 Zeilen aufgebaut ... basierend auf einer Verzeichnisstruktur ... dabei werden die aber noch nach Datum sortiert ... das Sortieren verbraucht nur einen Brauchteil (!!) der Zeit als das Einfügen in den Tree

Du kannst die Zeit für das aufbauen abkürzen in dem Du nicht den ganzen Tree erstellst, sondern nur den sichtbaren und für die nächste Ebene Dummy-Einträge erstellst (damit das Plus zu sehen ist)

hand, mogel


----------



## André Uhres (21. Mrz 2009)

@mogel: es geht um JTable


----------



## eso (23. Mrz 2009)

redbomber hat gesagt.:


> Wo kann der Fehler liegen?


Ich kann mir keinen Anwendungsfall vorstellen, wo wirklich 200000 Einträge gleichzeitig angezeigt werden müssen


----------



## Gast2 (23. Mrz 2009)

André Uhres hat gesagt.:


> @mogel: es geht um JTable


ach ja ... Swing zeichnet selber ... aber dennnoch bleibt das Problem das er alle Einträge anzeigen will ... das dürfte auf Swing in die Knie zwingen ... daher auch der Vorschlag nur die Einträge einzuhängen die gerade benötigt werden


----------



## Ebenius (23. Mrz 2009)

eso hat gesagt.:


> Ich kann mir keinen Anwendungsfall vorstellen, wo wirklich 200000 Einträge gleichzeitig angezeigt werden müssen


Das sind bei 100 Spalten doch grad mal 2000 Zeilen.

redbomber, kannst Du uns mal ein Beispiel zaubern, das ohne viel Zoom und Zeugs das gleiche Problem knackig zusammenfasst? Ohne Code kann man schlecht sagen, wo es teuer wird.

Ebenius


----------



## Wildcard (23. Mrz 2009)

mogel hat gesagt.:


> ach ja ... Swing zeichnet selber ... aber dennnoch bleibt das Problem das er alle Einträge anzeigen will ... das dürfte auf Swing in die Knie zwingen ... daher auch der Vorschlag nur die Einträge einzuhängen die gerade benötigt werden


Die Klassen sind in der Regel recht gut optimiert und zeichnen nur das nötigste. Man müsste sich also, wie Ebenius schon sagt, das konkrete Beispiel ansehen.


----------



## redbomber (23. Mrz 2009)

also ich kämpfe gerade damit bei mir den tptp profiler zu installieren ;P

--------------------------------------------------------------------------------------------------------------
Also die Grundlage meiner Daten sind Ergebnisse von vielen Berechnungen.
Es gibt wirklich sehr viele Daten. 200.000 sind dabei noch wenig.
Das ganze wird soll in einer Tabelle dargestellt werden, wobei man dann sozusagen über die Daten "scrollen" kann.
Da die JTable ja nur die Zellen darstellt, welche sichtbar sind, sollte die JTable hierfür eine sinnvolle und effiziente Darstellung sein.

Zusätzlich kann man auch noch rein/raus zoomen, d.h. in einer Zelle werden sozusagen 10 (20, 30 ...) Daten-Ergebnisse dargestellt. Und es gibt sogar eine Ansicht, wo man sich alle Daten in dem aktuellen Fenster darstellen lassen kann (dann sind z.b 8000 Daten-Ergbnisse je Zelle vorhanden).

Dargestellt werden die Zellen einfach mit einem Farbwert.
Dieser ergibt sich z.b. aus dem Durchschnitt der darin befindlichen Daten-Ergebnissen.


Also ich sehe ja ein, dass bei einer hohen Zoomstufe das ganze etwas länger dauert. Ebenso wenn ich die ZellGRÖßE verkleiner, so dass z.b. eine Zelle nur noch 4 Pixel gross ist und somit mehr Zellen auf den Bildschirm passen.

Aber wenn ich in Zoomstufe 1 das ganze betrachte (Zellgröße 15x15), dann scrollt die Scrollbar auch noch ewig langsam, obwohl dann in einer Zelle nur 1 Daten-Ergebnis steht.
Zu sehen sind dann bei mir im Vollbild etwa 50 Zeilen und 85 Spalten (Zelle 15x15 Pixel). Das macht dann 4250 Zellen die zu rendern sind.

@Ebenius:
Ich poste gleich mal meinen Renderer.
Dieser stellt die Zellen dar, welche die Daten-Werte enthält.


----------



## redbomber (23. Mrz 2009)

Hier nur ein Objekt, welches später benötigt wird:

```
protected LinkedList<Object> objectList= null;
protected StrandInformation strand = null;
protected int cellnumber = -1;
	
public ValuesInformation(LinkedList<Object> objectList, StrandInformation strand, int cellnumber){
		if(objectList== null || probes.isEmpty()) this.objectList= null;
		else this.objectList= objectList;
		
		this.strand = strand;
		this.cellnumber = cellnumber;
	}
	
	public int getCellnumber(){ 

		return this.cellnumber;
	}
	
	public StrandInformation getStrand(){
		return this.strand;
	}
	
	public LinkedList<Object> getValues(){
		return this.objectList;
	}
```


Hier mein Cellrenderer.
es werden immer zwei zeilen mit Daten dargestellt und darauf folgt dann eine zeile, welche eine scala enthält.
Dann wieder zwei Zellen Daten...usw.



```
public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int col) {

		ValuesInformation valInf = (ValuesInformation )master.getTableModel().getValueAt(row, col);

		cellTypeSelection(row, col, valInf , isSelected);	
		return this;	
}




protected void cellTypeSelection(int row, int col, ValuesInformation valInf , boolean isSelected){

		this.cellnumber = valInf.getCellnumber();
		StrandInformation strand = valInf .getStrand();

		if (cellnumber > master.getTableModel().getNumberOfNecessaryCells()) {
			setBackgroundColor(Color.BLACK);
	        } 
               else {
	                 // if so setBackgroundColor for cell
	                 if(valInf.getValues() == null){
                        setBackgroundColor(Color.GRAY);
	                } else {
                            LinkedList<Object> selectedValues = valInf .getValues();


		            // get value of experiment
		            Double doubleValue = null;
		            int expNumber = master.getExpNumber();
		            if (master.getSplitView() == SplitView.first) {

			          doubleValue = master.Value(selectedValues.getFirst())[expNumber];

		          } else if (master.getSplitView() == SplitView.mean) {
			         // hier wird einfach der Mean berechnet von allen Werten die sich in der Zelle befinden
			         doubleValue = getMean();

		           } else if (master.getSplitView() == SplitView.max) {
                                 // hier wird nach dem größten Wert gesucht
			         doubleValue = getMax();
			
		           } else if (master.getSplitView() == SplitView.min) {
                                // hier wird der kleinste Wert gesucht
			         doubleValue = getMin();
		            }

		// set background color or set opaque
		if (doubleValue != null) {
			// hier wird anhand des Wertes ein Farbwert berechnet
			setBackgroundColorForCell(doubleValue);
		} else {
			setOpaque(false);
		}
         }  	
}


// hier wird noch die Scala gepainted
// und zwar wird zuerst ein Buffered Image für die sichtbaren Zeilen im Fenster gezeichnet und
// hier wird dann Zelle für Zelle der Bereich aus dem Buffered Image ausgeschnitten und in die Zelle der Tabelle
// eingefügt
public void paintComponent(Graphics g) {
		super.paintComponent(g);
               setBackground(Color.WHITE);

		if (placeholderCell){
			if(master.getKindOfView().equals(KindOfView.WHOLE)){
				if (this.scalaImage != null) {
                                        // bestimme Größe einer Zelle und schneide diesen Bereich aus dem
                                        // buffered image aus
					int boxSizeX = master.getBoxSizeX();
					int boxSizeY = master.getBoxSizeY();
					Graphics2D g2d = (Graphics2D) g;
					g2d.drawImage(this.scalaImage, 0, 0, boxSizeX, boxSizeY,
							(placeHolderColumn - 1) * boxSizeX, 0,
							((placeHolderColumn - 1) * boxSizeX + boxSizeX),
							boxSizeY, this);
				} else {
					setBackground(Color.BLACK);
				}
			}
		} 
	}
```


----------



## Wildcard (23. Mrz 2009)

Spontan sehe ich da folgendes:
Dein renderer fragt das TableModel ab. Warum? Die Daten stehen in data.
Deine Methode cellTypeSelection scheint sehr viel zu tun (von aussen kann man schlecht sehen wie teuer die einzelnen Operationen sind). Du darfst nicht vergessen, das wird für jede Zelle bei jedem Zeichnen aufgerufen.


----------



## Ebenius (24. Mrz 2009)

Was soll setBackground(Color) in einer paintComponent(...)-Methode?
Wieso benutzt Du nicht das value-Argument, anstatt das TableModel nochmal abzufragen?
Wie langsam ist Deine JTable, wenn Du das Zeichnen des Bildes in paintComponent(...) auskommentierst
Erbt Dein Renderer von DefaultTableCellRenderer? Wenn nicht: Hast Du Dir schon mal den Quelltext des DefaultTableCellRenderer angesehen? Such mal nach "performance"!
Um herauszufinden, was da lange dauert, teste den Renderer in zwei Stufen mit Schleifen ohne Tabelle (Code im Browser getippt, don't blame me  ): [HIGHLIGHT="Java"]final TableCellRenderer render == YOUR_RENDERER;
final JTable table = new JTable();
long t0 = System.currentTimeMillis();
for (int row = 0; row < ROWCOUNT; row++) {
  for (int col = 0; col < COLCOUNT; col ++) {
    renderer.getTableCellRendererComponent(table, model.getValueAt(row, col),
        false, false, row, col);
  }
}
System.out.println("Took " + (System.currentTimeMillis() - t0) + "ms");

t0 = 0L;
final BufferedImage img = new BufferedImage(80, 25, BufferedImage.TYPE_INT_ARGB);
final Graphics g = img.getGraphics();
for (int row = 0; row < ROWCOUNT; row++) {
  for (int col = 0; col < COLCOUNT; col ++) {
    final Component comp = renderer.getTableCellRendererComponent(table,
          model.getValueAt(row, col), false, false, row, col);
    comp.setBounds(0, 0, 80, 25);
    comp.validate();
    t0 -= System.currentTimeMillis();
    comp.paint(g);
    t0 += System.currentTimeMillis();
  }
}
System.out.println("Painting took " + t0 + "ms");[/HIGHLIGHT]
Ebenius


----------



## redbomber (24. Mrz 2009)

> # Was soll setBackground(Color) in einer paintComponent(...)-Methode?



-> Also das habe ich nun heraus genommen,
ich setze jetzt nur noch zu beginn in 

```
public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int col)
```
einmal die hintergrundfarbe auf schwarz und wenn sich dann die Farbe ändert, wird die Farbe entsprechend gesetzt.
--------------------------------------------------------------------------------------------------


> # Wieso benutzt Du nicht das value-Argument, anstatt das TableModel nochmal abzufragen?





> #Dein renderer fragt das TableModel ab. Warum? Die Daten stehen in data.


-> gute Frage, habe ich jetzt geändert!

--------------------------------------------------------------------------------------------------


> #Wie langsam ist Deine JTable, wenn Du das Zeichnen des Bildes in paintComponent(...) auskommentierst


Also ich habe mal alles aus paintComponent auskommentiert, also auch das Zeichnen der Scale. Zudem habe ich die Möglichkeit die Scala auszuschalten, dann wird diese also garnicht gezeichnet.
Die GEschwindigkeit bleibt jedoch gleich!

---------------------------------------------------------------------------------------------------
Also mein Renderer:
Renderer extends JPanel implements TableCellRenderer 
Wo kann ich den Quelltext von dem DefaultTableCellRenderer betrachten?

---------------------------------------------------------------------------------------------------


----------



## Ebenius (24. Mrz 2009)

redbomber hat gesagt.:


> Wo kann ich den Quelltext von dem DefaultTableCellRenderer betrachten?


Im JDK-Installverzeichnis liegt ein src.zip. Da sind alle Quellen drin. Benutzt Du Eclipse? Dann CTRL+SHIFT+T, dann "DefaultTableCellRenderer" (oder einfach "DTCR" oder "DefTabCR") eingeben und ENTER drücken. Dann wird Dir entweder schon der Quelltext gezeigt, oder eine Seite wo ein Button mit "Attach Source" draufsteht; in letzterem Fall draufklicken, das oben erwähnte ZIP-File auswählen und glücklich werden.

Ebenius


----------



## Marco13 (24. Mrz 2009)

Ebenius hat gesagt.:


> Das sind bei 100 Spalten doch grad mal 2000 Zeilen.



"Gerade mal" ist gut. Versuch' mal, eine Tablelle mit 100 Spalte darzustellen. Wenn die in einer ScrollPane liegt, wird natürlich nur der relevante Bereich neugezeichnet, aber ... wer weiß, was in diesem Fall im painting code alles gemacht wird. (Hab's nicht alles nachvollzogen - der Satz oben erinnerte mich nur an die "Fisheye-Table", von der ich hier http://www.java-forum.org/codeschni...i-programmierung-meets-jogl-2.html#post478721 mal einen Screenshot gepostet hatte - die hat nur 375 Zeilen und 100 Spalten, und die hat schon 8000x6000 pixel gebraucht...


----------



## Ebenius (24. Mrz 2009)

Spielverderber.


----------



## redbomber (24. Mrz 2009)

gibt es eine Möglichkeit die src.zip separat herunter zu laden?
Habe keine src.zip in meinem Installationsverzeichnis.

Habe mir auch die neue SDK herunter geladen, da ist aber auch keine src.zip drinnen.


----------



## Ebenius (25. Mrz 2009)

Sofern Du von einem J2SDK (alias JDK) sprichst welches Du bei Sun heruntergeladen hast, halte ich das für vollkommen ausgeschlossen. Hast Du vielleicht nur das JRE installiert?

Ebenius


----------



## redbomber (25. Mrz 2009)

Also ich habe jetzt die Ursache für mein Problem gefunden:
Und zwar habe ich beim scrollen immer meine Table upgedatet.
Mache ich dies nich mehr, dann scrollt die Tabelle recht schnell.

DAs einzigste Problem ist dass dann nur meine Scala nicht immer mit gezeichnet wird,
aber ich hoffe dieses Problem noch zu lösen.


----------



## redbomber (25. Mrz 2009)

ja ich habe nur das JRE


----------



## Ebenius (25. Mrz 2009)

redbomber hat gesagt.:


> Also ich habe jetzt die Ursache für mein Problem gefunden:
> Und zwar habe ich beim scrollen immer meine Table upgedatet.
> Mache ich dies nich mehr, dann scrollt die Tabelle recht schnell.


Autsch.



redbomber hat gesagt.:


> DAs einzigste Problem ist dass dann nur meine Scala nicht immer mit gezeichnet wird,
> aber ich hoffe dieses Problem noch zu lösen.


Da kann ich Dir grad nicht helfen. Am besten Du beschreibst das Problem nochmal in einem neuen Thema.



redbomber hat gesagt.:


> ja ich habe nur das JRE


Dann installier Dir zum Entwickeln das SDK! Da sind die Quellen dabei und auch die Entwicklungstools, wenn Du außerhalb IDE bauen möchtest.

Ebenius


----------

