# PerformanceProbleme(Beim Scrollen ruckelt es)



## MisterDan (21. Feb 2008)

Hi Leute,

mein Programm hat ein DrawPanel wo eine große (2000x2000 Pixel) Grafik drauf liegt.
Wenn ich jetzt mit den Scrollbalken scrolle, dann ruckt das Bild total.

Hier sind die Methoden die ich zum zeichnen verwende.


```
/*
*
*Wir aufgerufen sobald, irgendwas neu gezeichnet werden muss. Z.B. wenn man mit der Maus ins DrawPanel klickt *(um einen Waypoint zu setzen)
*
*/
	public void updateUserInterface(){
		Graphics g = getGraphics();
		if (g != null)
			redrawGraphics(g);
	}
	
	public void paint(Graphics g){
		//g = this.bi.createGraphics();
		redrawGraphics(g);
	}
	
/*
*
* Hier wird alles gezeichnet. Ich vermute das dass Performance Problem hier liegt.
*
*/
	private void redrawGraphics(Graphics g){
		//initialize Antialiasing
		Graphics2D g2d = this.bi.createGraphics();
		//Graphics2D g2d = (Graphics2D) g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		if(!mouseEvent){
			//Screen erneuern
			if(!mapLoaded){
				g2d.setColor(Color.gray);
				g2d.fillRect(0,0,getWidth(), getHeight());
			}
			
			//Map neu zeichnen
			if(mapLoaded){
				tileMap.draw(g2d);
				//Graphics graphics = this.buffer.getDrawGraphics(); 
				//graphics.drawImage(this.bi, 0, 0, null);
//				if(!this.buffer.contentsLost()){
//					this.buffer.show();
//				}
			}
		}
		
		Iterator<Connection> cIter = wpController.getCList().values().iterator();
		while(cIter.hasNext()){
			Connection c = cIter.next();
			
			g2d.setColor(connectionColor);
			g2d.setStroke(new BasicStroke(4.0f));
			g2d.drawLine(c.getStartX(), c.getStartY(), c.getEndX(), c.getEndY());
			
			int middleX = calculateMiddlePointX(c.getStartX(), c.getEndX());
			int middleY = calculateMiddlePointY(c.getStartY(), c.getEndY());
			
			g2d.setColor(connectionColor);
			g2d.fillOval(middleX-5, middleY-15, 30, 40);
			g2d.setColor(Color.white);
			g2d.setFont(cFont);
			g2d.drawString(""+c.getConnectionID(), middleX+6, middleY);
			g2d.drawString(""+c.getWeight(), middleX+2, middleY+17);
		}
		
		Iterator<Waypoint> wIter = wpController.getWpList().values().iterator();
		while(wIter.hasNext()){
			Waypoint wp = wIter.next();
			
			int xcoord = wp.getXPos();
			int ycoord = wp.getYPos();
			
			g2d.setColor(waypointColor);
			g2d.setStroke(new BasicStroke(4.0f));
			g2d.fillOval(xcoord-25, ycoord-25, 50, 50);
			
			if(wp.getWaypointID()<10){
				g2d.setFont(wpInnerFont);
				g2d.setColor(wpInnerFontColor);
				g2d.drawString(""+wp.getWaypointID(), xcoord-2, ycoord+5);
				g2d.setFont(wpOuterFont);
				g2d.setColor(wpOuterFontColor);
				g2d.drawString(wp.getName(), xcoord-30, ycoord-25);
			} else {
				g2d.setFont(wpInnerFont);
				g2d.setColor(wpInnerFontColor);
				g2d.drawString(""+wp.getWaypointID(), xcoord-6, ycoord+5);
				g2d.setFont(wpOuterFont);
				g2d.setColor(wpOuterFontColor);
				g2d.drawString(wp.getName(), xcoord-30, ycoord-30);
			}
		}
		mouseEvent = false;
		
		//double buffering
		  Graphics graphics = this.buffer.getDrawGraphics();
		  graphics.drawImage(this.bi, 0, 0, null);
		  if (!this.buffer.contentsLost()) {
		   this.buffer.show();
		  }

		  if (graphics != null) {
		   graphics.dispose();
		  }
		  if (g2d != null) {
		   g2d.dispose();
		  }
		
	}
```

Wenn ihr den ganzen Programmcode benötigt um mir auf die Sprünge zu helfen stell ich den gerne auch zu Verfügung. Mein Programm ist schon echt weit (fast fertig), nur noch dieses nicht-lösbare-Performance-Problem.

Achja ich hab ein Intel2CoreDuo Notebook, mit ner GeForce 7300Go(512Mb), 2GB Ram und WindowsXP, falls das irgendwie weiter hilft.


Habt jetzt schonmal tausend Dank! Ich steck total in der Klemme, denn am Dienstag ist Projektabgabe^^

Mfg

MisterDan


----------



## Marco13 (21. Feb 2008)

Wenn die Tiles nur ein Hintergrundbild sind, solltest du vmtl. das AntiAliasing erst einschalten, NACHDEM du die Tiles gezeichnet hast. (Wie auch immer man es macht: AntiAlisaing fißt unglaublich viel Rechenleistung  :shock: )

Ansonsten wäre noch ganz interessant, um wie viele "Waypoints" es in der while-Schleife geht.... Viele drawStrings können auch sehr teuer ein.

Dass man solche Sachen wie

```
g2d.setColor(connectionColor);
g2d.setStroke(new BasicStroke(4.0f)); 

// Wurde - ohne dass zwischendurch die Farbe geändert wurde! - nochmal aufgerufen:
g2d.setColor(connectionColor);
```
nur EIN mal (VOR der Schleife) machen sollte, sollte klar sein, aber bei "wenigen" Waypoints kann man damit wohl nicht sooo viel rausreißen....

EDIT: Nachtrag: Bei Swing brauchst du kein DoubleBuffering per Hand zu implementieren - sowas wie "getGraphics" ist auf Components fast(!) immer falsch, poste ggf. mal die vollständige Klasse oder mehr Infos dazu...


----------



## Wildcard (21. Feb 2008)

Marco13 hat gesagt.:
			
		

> Wenn die Tiles nur ein Hintergrundbild sind, solltest du vmtl. das AntiAliasing erst einschalten, NACHDEM du die Tiles gezeichnet hast. (Wie auch immer man es macht: AntiAlisaing fißt unglaublich viel Rechenleistung  :shock: )


Darum sollte sich doch eigentlich die GPU kümmern  ???:L


----------



## Marco13 (21. Feb 2008)

Was genau von der GPU und was von der CPU übernommen wird, ist schwer zu sagen, aber... ein einfaches Bild mit Antialiasing zu zeichnen macht IMHO i.a. keinen Sinn - also kann man ja den Rechner (egal ob GPU oder CPU) ein bißchen entlasten. Spart auch Strom, und verhindert somit die anstehende Klimakatastrophe :wink:


----------



## MisterDan (21. Feb 2008)

Hallo, danke erstmal für die schnellen Antworten.
Hab es grade komplett ohne Anti Aliasing ausprobiert und das Rucken ist nicht besser geworden.

Also, ich hab jetzt das DoubleBuffering komplett rausgenommen.

Ich würde auch gerne das komplette Programm zur Verfügung stellen, wenn es gewünscht wird 
Hier nochmal die Komplette DrawPanel.java


```
package local.gui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Iterator;

import javax.swing.JPanel;

import local.persistance.mapLoader.TileMap;

@SuppressWarnings("serial")
public class DrawPanel extends JPanel {

	
    private boolean mouseEvent;
    private boolean mapLoaded;
    private int x;
    private int y;
    
    private Font wpOuterFont;
    private Font wpInnerFont;
    private Font cFont;
    private Color wpInnerFontColor;
    private Color wpOuterFontColor;
    private Color waypointColor;
    private Color connectionColor;
    
    private TileMap tileMap;
    private WPEditorController wpController;
    
	public DrawPanel(final WPEditorController wpController){
		
		this.wpController = wpController;
//		this.drawPaneDimension = null;
//		this.setBackground(Color.gray);

		
		this.wpOuterFont = new Font("SansSerif", Font.BOLD, 15); 
		this.wpInnerFont = new Font("SansSerif", Font.TYPE1_FONT,  12); 
		this.cFont = new Font("SansSerif", Font.PLAIN, 9);
		this.waypointColor = new Color(51,102,153);
		this.connectionColor = new Color(51,102,153);
		this.wpInnerFontColor = new Color(255, 255, 255);
		this.wpOuterFontColor = new Color(0,0,0);
		this.mouseEvent = false;
		this.mapLoaded = false;
		this.addMouseListener(new MouseAdapter(){
			public void mouseClicked(MouseEvent event){
						
				x = event.getX();
				y = event.getY();

				mouseEvent = true;
				wpController.doLogic(x, y);
			}
		});
	}
	
	public void updateUserInterface(){
		Graphics g = getGraphics();
		if (g != null)
			redrawGraphics(g);
	}
	
	public void paint(Graphics g){
		//g = this.bi.createGraphics();
		redrawGraphics(g);
	}
	
	private void redrawGraphics(Graphics g){
		//initialize Antialiasing
		Graphics2D g2 = (Graphics2D) g;
		//g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		if(!mouseEvent){
			//Screen erneuern
			if(!mapLoaded){
				g2.setColor(Color.gray);
				g2.fillRect(0,0,getWidth(), getHeight());
			}
			
			//Map neu zeichnen
			if(mapLoaded){
				tileMap.draw(g2);
				//Graphics graphics = this.buffer.getDrawGraphics(); 
				//graphics.drawImage(this.bi, 0, 0, null);
//				if(!this.buffer.contentsLost()){
//					this.buffer.show();
//				}
			}
		}
		
		Iterator<Connection> cIter = wpController.getCList().values().iterator();
		while(cIter.hasNext()){
			Connection c = cIter.next();
			
			g2.setColor(connectionColor);
			g2.setStroke(new BasicStroke(4.0f));
			g2.drawLine(c.getStartX(), c.getStartY(), c.getEndX(), c.getEndY());
			
			int middleX = calculateMiddlePointX(c.getStartX(), c.getEndX());
			int middleY = calculateMiddlePointY(c.getStartY(), c.getEndY());
			
			g2.setColor(connectionColor);
			g2.fillOval(middleX-5, middleY-15, 30, 40);
			g2.setColor(Color.white);
			g2.setFont(cFont);
			g2.drawString(""+c.getConnectionID(), middleX+6, middleY);
			g2.drawString(""+c.getWeight(), middleX+2, middleY+17);
		}
		
		Iterator<Waypoint> wIter = wpController.getWpList().values().iterator();
		while(wIter.hasNext()){
			Waypoint wp = wIter.next();
			
			int xcoord = wp.getXPos();
			int ycoord = wp.getYPos();
			
			g2.setColor(waypointColor);
			g2.setStroke(new BasicStroke(4.0f));
			g2.fillOval(xcoord-25, ycoord-25, 50, 50);
			
			if(wp.getWaypointID()<10){
				g2.setFont(wpInnerFont);
				g2.setColor(wpInnerFontColor);
				g2.drawString(""+wp.getWaypointID(), xcoord-2, ycoord+5);
				g2.setFont(wpOuterFont);
				g2.setColor(wpOuterFontColor);
				g2.drawString(wp.getName(), xcoord-30, ycoord-25);
			} else {
				g2.setFont(wpInnerFont);
				g2.setColor(wpInnerFontColor);
				g2.drawString(""+wp.getWaypointID(), xcoord-6, ycoord+5);
				g2.setFont(wpOuterFont);
				g2.setColor(wpOuterFontColor);
				g2.drawString(wp.getName(), xcoord-30, ycoord-30);
			}
		}
		mouseEvent = false;
	}
	
	public int calculateMiddlePointX(int startX, int endX){
		return (startX+endX)/2;
	}
	
	public int calculateMiddlePointY(int startY, int endY){
		return (startY+endY)/2;
	}
	
	/*
	 * SETTER
	 */
	public void setTileMap(TileMap map){
		this.tileMap = map;
	}
	
	public void setMapLoaded(boolean loaded){
		this.mapLoaded = loaded;
	}
}
```

P.S.:Auf einem MacBook läuft es problemlos. - Keine Ruckler, einwandfrei!
Liegt wahrscheinlich daran das Mac, Java-Dateien automatisch in OpenGL (um)rendert. Windows macht das nicht. Vll. muss man Java auch sagen, das es die Grafikartenbeschleuniger ansprechen soll oder und das ganze quasi gar nicht programmier-technisch lösen, sondern Einstellungen im System oder sonst wo durchführen. (Wahrscheinlich ne Schnapsidee^^)

Vielen Dank und Grüße

MisterDan


----------



## Wildcard (21. Feb 2008)

Auf Bilder wird Antialiasing doch auch nicht angewendet, das ist doch nur stumpfes Pixel kopieren


----------



## MisterDan (21. Feb 2008)

Wildcard hat gesagt.:
			
		

> Auf Bilder wird Antialiasing doch auch nicht angewendet, das ist doch nur stumpfes Pixel kopieren



ne damit hat es auch offensichtlich nichts zu tun. 
Gibt es nicht irgendwie die Möglichkeit Java zu sagen, dass er beim Zeichnen auf Direct3D bzw. auf den Grafikkartenbeschleuniger zugreifen soll?


----------



## Wildcard (21. Feb 2008)

MisterDan hat gesagt.:
			
		

> Gibt es nicht irgendwie die Möglichkeit Java zu sagen, dass er beim Zeichnen auf Direct3D bzw. auf den Grafikkartenbeschleuniger zugreifen soll?


Das passiert automatisch. Ich würde den Fehler eher in zB deinem Buffering vermuten.
Benutz doch Swing und lass es den JFrame selbst erledigen.


----------



## MisterDan (21. Feb 2008)

Wildcard hat gesagt.:
			
		

> MisterDan hat gesagt.:
> 
> 
> 
> ...


----------



## Wildcard (21. Feb 2008)

Zunächst mal wird in Swing nicht paint, sondern paintComponent überschrieben.
getGraphics ist verboten. Neu gezeichnet wird mit repaint.


----------



## MisterDan (21. Feb 2008)

Wildcard hat gesagt.:
			
		

> Zunächst mal wird in Swing nicht paint, sondern paintComponent überschrieben.


ok ich überschreibe nun paintComponent anstatt paint.



> getGraphics ist verboten. Neu gezeichnet wird mit repaint.



was heisst getGraphics ist verboten? Wenn du mal in meine Methode updateUserInterface schaust. Dann muss ich doch sowas wie getGraphics machen, ich meine sonst hab ich ja gar kein Graphics-Objekt was ich an meine "redrawGraphics"-Methode übergeben kann.

Oder nicht??

Wie oder wann würdest du denn repaint aufrufen bzw. überschreiben?
Wir repaint nicht automatisch von Swing aufgerufen?


----------



## Wildcard (21. Feb 2008)

Man zeichnet in paintComponent. Wenn deine Anwendung der Meinung ist das sich etwas geändert hat rufst du repaint auf, der EDT wird dann deine paintComponent aufrufen.
In Swing zeichnet man passiv, daher verbietet sich auch getGraphics


----------



## MisterDan (21. Feb 2008)

Wildcard hat gesagt.:
			
		

> Man zeichnet in paintComponent. Wenn deine Anwendung der Meinung ist das sich etwas geändert hat rufst du repaint auf, der EDT wird dann deine paintComponent aufrufen.
> In Swing zeichnet man passiv, daher verbietet sich auch getGraphics



ok wenn der Nutzer also den Scrollbalken bewegt ist mein Programm der Meinung, dass sich etwas geändert hat.
Darauf soll ich als Programmier mit repaint reagieren?
Nur woher weiss weiß repaint WAS genau es (neu) zeichnen soll?

Sorry, aber was meinst du mit EDT?

Langsam versteh ich aber was du damit meinst das getGraphics verboten ist, nur ich weiss immernoch nicht wie ich es anders machen sollte...


danke
mfg
MisterDan


----------



## anfänger15 (21. Feb 2008)

Wenn du den scrollbalken bewegst zeichnet Swing normal automatisch neu da musst du gar nichts machen.

In Swing wird in der paintComponent methode gezeichnet, das heißt du schreibst alles was etwas zeichnet in diese methode und löscht deine andere. In der paintComponent methode hast du dann bereits ein Graphics Objekt welches du wenn du Graphics2D benötigst nur noch in ein Graphics2D Objekt casten musst. Du musst also nie createGraphics/getGraphics oder so aufrufen.


----------



## MisterDan (21. Feb 2008)

jaa ich verstehe was du meinst.

macht auch sinn 

Ich habe jetzt quasi nur noch meine paintComponent-Methode in meiner Klasse "DrawPanel", soweit sogut.
Leider ruckt es beim Scrollen immer noch. (zwar nicht mehr ganz so extrem aber immer noch sehr unschön & inakzeptabel)
Zum anderen merkt mein Programm jetzt nicht mehr wenn ich Waypoints setze. 
Also wenn ich ins DrawPanel klicke wird normalerweise ein Waypoint in eine Hashtable geschrieben und dann wird 

```
drawPanel.updateUserInterface();
```

aufgerufen.

Da ich ja jetzt nur noch die paintComponent-Methode habe, muss ich ja


```
drawPanel.repaint();
```
 aufrufen? Richtig? - Das klappt auch.

Nur wenn ich im FileChooser meine Map ausgewählt habe und auf öffnen klicke, wird die map quasi auch geöffnet, nur nicht mehr angezeigt. Ich muss jetzt erst mein Fenster verkleinern oder vergrößern damit ein entsprechendes Event ausgelöst wird, was meinem DrawPanel de repaint-Befehl gibt.

Aber das Problem ist eigentlich nur noch, das es trotz alldem immernoch ruckt.

Aber ich glaube ich / wir sind kurz vorm Ziel.

Hat jemand noch ne idee, wie man es irgendwie besser hinkriegen kann?

Tausend Dank, viel Grüße
MisterDan


----------



## Wildcard (22. Feb 2008)

Zeig mal aktualisierten Code.


----------



## MisterDan (23. Feb 2008)

ähh ja moin,

also ein Kommilitone hat mir jetzt geholfen. Und das Problem lag ganz woanders. 

Die ganzen Tile-Grafiken (ca. 4000 Stück), werden halt 20 mal pro Sekunde neu gezeichnet wenn man die Scrollbar bewegt.
Er lässt einfach alle 4000 Bilder in mehrere 500x500 Pixel grosse Bilder zeichnen.
Nun müssen nur noch ca. 10 Bilder so oft neu gezeichnet werden und nicht 4000.

Ich möchte mich trotzdem herzlich für eure nette Unterstützung bedanken.

Mfg

MisterDan


----------

