# eine nullpointerexception, wo sie nicht sein sollte



## Stormblade (27. Okt 2012)

Hallo, aus mir unerfindlichen Gründen bekomme ich in meinem neuen projekt eine NullPointerException. Hierzu mein code:


```
public class Spieloberfläche extends JPanel{

  Painter painter;

  public Spieloberfläche(){
    super();
    painter = new Painter(this);
    painter.start();
    this.setFocusable(true);
  }
	
  public void paint(Graphics g){
    super.paint(g);
  }
}

public class Painter extends Thread{

  Graphics g = null;
  JPanel parent = null;

  public Painter(JPanel parent)	{
    this.parent = parent;
  }

  public void paint(){
    g = parent.getGraphics();
    g.setColor(Color.blue);
  }			

  public void run(){
    this.paint();
  }
}
```
Schon bei der setColor-Methode bekommt mein programm probleme... g ist zu dem Zeitpunkt noch mit "null" belegt, doch ich kann mir das beim besten Willen nicht erklären, denn in einem anderen Programm habe ich dies genau gleich gemacht, mit erfolg.
Ich hoffe nur, dass mich jemand auf einen Fehler aufmerksam machen kann


----------



## Tomate_Salat (28. Okt 2012)

Ich kann dich leider auf 2 Fehler aufmerksam machen ;-). Beim Zeichnen mit von Swing tut man folgendes nicht:

1) man überschreibt bei swing nicht die paint-Methode (du hast effektiv zwar nix geändert, aber der Ansatz ist ja da)
2) man arbeitet nicht mit getGraphics.

Richtig wäre es, wenn du die paintComponent()-Methode überschreibst und dort auch das Zeichnen durchführst. 

Dann noch so am Rande:
Umlaute sind ein hässliche Geschichte, die ich vermeiden würde. Also lieber: Spieloberflaeche. Dann hast du auch ein English-Deutsch-Gemisch. Letzendlich würde ichs einfach GamePanel nennen.


----------



## Stormblade (28. Okt 2012)

Hm ok danke, ich werd mich um einen besseren programmierstil bemühen  
Kann mir dennoch jemand vielleicht ein klitzekleines programm schreiben, in dem es wie oben 2 klassen (ohne die mainmethode) gibt? In der ersten klasse soll das JPanel sein und in der zweiten Klasse (die einen Thread extended) wird in das JPanel ein viereck hineingezeichnet. Kann mir da jemand ein beispiel machen? Damit wär mir glaub ich am besten geholfen


----------



## Melfis (28. Okt 2012)

```
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Calendar;
import java.util.GregorianCalendar;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class JPaintPanel extends JPanel {

	BufferedImage bi;
	final Painter p;

	public JPaintPanel() {
		this.setPreferredSize(new Dimension(400, 400));
		bi = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);
		p = new Painter(this);
		p.start();
	}

	public BufferedImage getBufferedImage() {
		return bi;
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		synchronized (bi) {
			g.drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), Color.WHITE,
					null);
		}

	}

	public static void main(String[] args) {
		JFrame jfr = new JFrame("Test");
		jfr.getContentPane().add(new JPaintPanel());
		jfr.pack();
		jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jfr.setVisible(true);
	}

}

class Painter extends Thread {
	JPaintPanel jpp;
	Calendar calendar = new GregorianCalendar();
	int second=0;

	public Painter(JPaintPanel jpp) {
		this.jpp = jpp;
	}

	public void run() {
		while (true) {
			if (second != Calendar.getInstance().get(Calendar.SECOND)) {
				second = Calendar.getInstance().get(Calendar.SECOND);
				synchronized (jpp.getBufferedImage()) {
					Graphics2D g2 = jpp.getBufferedImage().createGraphics();
					g2.clearRect(0, 0, 400, 400);
					g2.translate(200, 200);
					g2.rotate(second / 30.0 * Math.PI);
					g2.drawLine(0, 0, 0, -100);
				}
				jpp.paintImmediately(100, 100, 200, 200);
			} else {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

}
```

Quelltext ohne Gewähr! Ich bin nicht so der Swing/Thread experte 

MFG Melfis


----------



## Spacerat (28. Okt 2012)

Tomate_Salat hat gesagt.:


> 2) man arbeitet nicht mit getGraphics.


@TO: Das hat weniger mit besserem Programmierstil zu tun, als mit Fehlerträchtigkeit. Besagtes "getGraphics()" sorgt nämlich unterumständen für deine NPE.
Ein klitzekleines Programm ist auch nicht nötig. Wenn du deine "Verrenkungen" (inkl. "getGraphics()") eine "paint()"-Methode zu implementieren lassen würdest und statt dessen die bereits vorhandene "repaint()"-Methode verwenden würdest, ist scheinbar alles okay mit deinem. 
[EDIT]Melfis Code wäre auch 'ne Möglichkeit. Aber @Melfi: Kann es sein, dass du da etwas zu viel synchronisierst?[/EDIT]


----------



## vanny (28. Okt 2012)

```
import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class ZeichenPanel extends JPanel{
	

	private static final long serialVersionUID = 1L;
	private int pX, pY;

	
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		g.setColor(Color.RED);
		g.fillRect(pX, pY, 30, 10);
		System.out.println("Neu gezeichnet an Position: " + pX + ", " + pY);
	}
	
	public void drawOnNewPosition(int pX, int pY){
		this.pX = pX;
		this.pY = pY;
		repaint();
	}
	
	public static void main(String[] args) {
		JFrame fr = new JFrame();
		fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		fr.setSize(600, 400);
		
		ZeichenPanel zPnl = new ZeichenPanel();
		fr.add(zPnl);
		
		ZeichenThread zTh = new ZeichenThread(zPnl);
		fr.setVisible(true);
		zTh.start();
		
	}

}
```


```
public class ZeichenThread extends Thread{
	
	private ZeichenPanel zPnl;
	
	public ZeichenThread(ZeichenPanel zPnl){
		this.zPnl = zPnl;
	}
	
	public void run(){
		if(zPnl!=null){
			while(true){
				int pX = (int)(Math.random()*600);
				int pY = (int)(Math.random()*400);
				 zPnl.drawOnNewPosition(pX, pY);
				 System.out.println("Neuzeichnen angestoßen an " + pX + ", " + pY);
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

}
```

edit: eben ma hinproggen dauert hier echt zu lange


----------



## Melfis (28. Okt 2012)

@Spacerat: Dann bekomm ich eklige Artefakte, bzw. es werden unfertige Zeichnungen ausgegeben. Deswegen die Syncro-Blöcke, ich bin aber für Verbesserungsvorschläge offen!

MFG Melfis


----------



## Spacerat (28. Okt 2012)

[OT]@Melfis: War ehrlich gesagt nur 'ne Frage. Ich hatte mal ähnliches programmiert, bis sich die beiderseitige Synchronisation gravierend auf die FPS niederschlug. Habe dann nur eine Seite (jene, in der das Image gezeichnet werden sollte) synchronisiert und es hatte keinen negativen Effekt aber die FPS waren wieder da. Das kann Zufall sein oder aber auch daran liegen, dass *synchronized* den Zugriff auf das komplette Objekt inkl. Methodenaufrufe für andere Threads sperrt. So Fit bin ich auch nicht in Sachen Threads.[/OT]


----------



## Stormblade (28. Okt 2012)

Ok, ich danke euch sehr für eure bemühungen mir zu helfen   . Wenn ich das richtig verstanden habe, versucht ihr mir alle zu zeigen, dass ich in der JPanel-Klasse etwas zeichnen soll, und dieses gezeichnete "objekt" dann in einer Thread-Klasse verändern kann  oder? 
In meinem Fall ist es jetzt so, dass ich ungefähr an die 70 aufwärts bilder in mein JPanel zeichnen will. Da ich meine JPanel-klasse nicht so aufblähen will, müsste ich doch auch den zeichenvorgang erst in der Thread-klasse starten können oder? So dass ich in der Thread-Klasse befehle: Zeichne jetzt in das JPanel der Über-Klasse ein rechteck hinein, das dort noch nicht definiert wurde  Vielleicht habe ich eure codes auch nicht richtig verstanden, könnt ihr mir bitte auf dieses anliegen nochmal antworten?


----------



## vanny (28. Okt 2012)

Klares Jain

Das Zeichnen auf das JPanel gehört in die 
	
	
	
	





```
paintComponent();
```
 und nur da hin und auch *nur* das Zeichnen.
Es ist ja letztendlich nur ein Bild auf dem JPanel zu sehen (die Summe aller dazustellenden Dinge eben).
Dann kannst du natürlich extern ein BufferedImage zusammenmalen und dieses dann von der paintComponent-Methode zeichnen lassen.

Gruß Vanny


----------



## Melfis (28. Okt 2012)

Ich beziehe mich jetzt mal auf mein Beispiel:

Der seperate Thread erledigt allgemeine Rechnungen und zeichnet die Abbildung in das Buffered Image. Das JPanel zeichnet das Buffered Image nur noch auf seine Oberfläche. So bleibt der EDT frei und die Swing GUI kommt nicht ins Stocken.


----------



## Stormblade (28. Okt 2012)

Ok, gecheckt   Dann werd ich das genauso machen. Ich versuch mal ein BufferedImage zusammenzumalen, wenn ich nicht weiterkomm, dann werd ich wieder fragen


----------



## Stormblade (28. Okt 2012)

Okidoki, vielen dank vanny und melfis für eure unterstützung, ich zeichne jetzt immer in der run()-methode das BufferedImage zusammen, welches dann in der PaintComponent()-methode ausgegeben wird  Ich hoffe das ist performant genug, um zig positionsberechnungen + zeichnen von ca 70 Elementen, mindestens 24 mal pro sekunde auszuführen 
Nochmals vielen Dank :toll:


----------

