Graphics Objekt liefert null

kaoZ

Top Contributor
Kann mir vielleicht schnell einer sagen ob meine Vermutung richtig ist, warum g2 hier null liefert?

Ich vermute weil der panel / dessen Graphics Objekt noch nicht vollständig initialisiert ist,
und ich versuchen mit diesem direkt zu zeichnen.

Die betreffende stelle ist markiert, egal wie ich auch versuche an das vollständig initialisierte Objekt zu gelangen fliegt hier immer eine NPE.

Witzigerweise beim debuggen nicht o0.....

Java:
public class GamePanel extends JPanel implements Runnable, KeyListener{
    private static final long serialVersionUID = 1L;
    
    //properties
    static int WIDHT	 = 320;
    static int HEIGHT	 = 240;
    static int SCALE	 = 2;
    
    //image
    BufferedImage image;
    Graphics g;
    
    //gameloop
    Thread gameLoop;
    boolean running;
    static int FPS = 60;
    static int targetTime = 1000 / FPS;

    public GamePanel() {
    	setProperties();
    	initialise();
	    startGameLoop();
    }
    
    private void setProperties(){
    	setPreferredSize(new Dimension(WIDHT *SCALE, HEIGHT * SCALE));
    	setFocusable(true);
    	requestFocus();
    }
    
    private void initialise(){
    	
    	image = new BufferedImage(WIDHT, HEIGHT, BufferedImage.TYPE_INT_RGB);
    	
    	g = image.getGraphics();
    	
    	running = true;
    }
    
    private void startGameLoop(){
    	
    	if(gameLoop == null){
    		gameLoop = new Thread(this);
    		gameLoop.start();
    	}
    }
    
    private void update() {}
    private void render() {}
    
    private void draw() {
    	
    	Graphics g2 = getGraphics();  // <-- bleibt null / ggf. weil panel noch nicht komplett initialisiert ?!
    	g2.drawImage(image, 0, 0, WIDHT, HEIGHT, null);
    	g2.dispose();
    }
    
	@Override
    public void keyTyped(KeyEvent e) {}

	@Override
    public void keyPressed(KeyEvent e) {}

	@Override
    public void keyReleased(KeyEvent e) {}

	@Override
    public void run() {
	    
		update();
		render();
		draw();
		
		try {
	        Thread.sleep(1000);
        } catch (Exception e) {
	        // TODO: handle exception
        }
    }

}

Das hier kommt beim debuggin heraus :

Was mich hier irritiert ist das laut Belegung hier ein Graphics2D Objekt geliefert wird, das ist hier aber nicht der Fall ......



Keine Exception !


und das hier wenn ich es normal ausführe :

Code:
Exception in thread "Thread-1" java.lang.NullPointerException
	at dev.eflow.game.main.GamePanel.draw(GamePanel.java:67)
	at dev.eflow.game.main.GamePanel.run(GamePanel.java:85)
	at java.lang.Thread.run(Unknown Source)

also fliegt quasi hier die NPE

Java:
    	g2.drawImage(image, 0, 0, WIDHT, HEIGHT, null);

    // g2 ist hier angeblich null, aber warum dann beim debugging nicht ?
 
Zuletzt bearbeitet:

kaoZ

Top Contributor
Wenn ich aber während der Normalen Ausführung

Java:
if(g2 == null){
  System.out.println("g2 == NULL");
  System.exit(0);
}

scheint die Annahme doch korrekt zu sein das g2 null ist , aber warum passiert das nicht beim Debuggen,

und liegt dann doch daran das vielleicht das Graphics Objekt noch nicht vollständig Initialisiert wurde , und falls dem so sein sollte, warum ? und wo kann ich sonst das vollständig Initialisierte Objekt herbekommen da ich dies ja brauche um direkt zu zeichnen, oder sollte vielleicht der erste aufruf von draw(); verzögert stattfinden ?
 

turtle

Top Contributor
Das Graphics-Objekt ist in der Tat nicht vollständig initialisiert.

Dieses nennt man "Realization" und geschieht u.a. wenn ein Objekt sichtbar gemacht wird.

Ich habe mal zwei Links dazu (eins und zwei)
 

kaoZ

Top Contributor
Ich bin Grade nicht Zuhause, aber da ich hier von JPanel ableite und somit nur vollständig initialisieren kann wenn ich das Objekt erstellt habe, bleibt nur also quasi nur der Weg nicht abzuleiten und einfach eine Referenz auf ein Jpanel zu halten und dann mit getter zu arbeiten, sprich schon vorher das panel vollständig zu initialisieren und mir dann das graphics Objekt zu holen ? Was ich nicht verstehe ist das es im tutorial auch so gemacht wird, da scheint es ohne Probleme zu funktionieren, ich habe lediglich das starten des gameloops am anderer Stelle realisiert, ob es damit zusammenhängen könnte? Das tutorial ist das was ich bereits im letzten Post erwähnt hatte, ich hab leider vom Handy aus den link Grad nicht parat, aber das beschäftigt mich jetzt :-D
 

Thallius

Top Contributor
Ich finde es nicht besonders geschickt die GameLoop in ein Panel zu packen. Die GameLoop gehört in einen Controller und nich in einen View (MVC Pattern)

Warum machst du das ?

Gruss

Claus
 

kaoZ

Top Contributor
Zum testen hielt ich es nicht die nötig es nach einem pattern umzusetzen, bzw. den thread auszulagern, ob ich es später so umsetze ist natürlich möglich, sobald ich das graphics Problem gelöst habe ;)

Mal angesehen davon hab ich mich an einen tutorial orientiert welches ebenfalls den gameloop im panel realisiert hat, allerdings erzeugt und startet er diesen in einer überschrieben addNotify() Methode, was ja an und für sich keinen Unterschied machen sollte
 

kaoZ

Top Contributor
Ich bin erst Mittwoch wieder Zuhause, turtle hat du damit schon Erfahrung? bzw. Steht darüber vielleicht was in dem Buch welches du erwähnt hattest ?

Oder ich muss dann wirklich erst den Lösungsansatz mit der Referenz auf ein JPanel ausprobieren :)
 
Zuletzt bearbeitet:

turtle

Top Contributor
Also, in dem angesprochenen Buch, finde ich nichts über ein Problem mit der Realization von JPanels gelesen;)

Ich glaube aber auch, das dein Code maximal von Swing und der JVM entkoppelt sein sollte.

Dies bedeutet, das du das JPanel "normal" erzeugen solltest und dann darauf anschliessend deinen GameLoop-Thread anwenden solltest.

Hier wird im Buch, zu Recht, angemerkt, das du dir den Graphics-Kontext jedesmal neu holen solltest, um nicht mit Swing/OS in Konflikt zu kommen.

In Pseudo-Code sieht das so aus:
Java:
    public void run() {
	running = true;
	while (running) {
	    gameUpdate(); // game state is updated
	    gameRender(); // render to a buffer
	    paintScreen(); // draw buffer to screen
	}
    }
private void paintScreen( ) {
 Graphics g;
 try {
 g = this.getGraphics( ); // get the panel's graphic context
...
}
 

kaoZ

Top Contributor
Ich werd mir das ganze Mittwoch mal in Ruhe anschauen und den gameloop dann mal auslagern, das Jpanel mal nicht ableiten sondern normal instanzieren und mal schauen wohin mich das führt.
Was ich mich natürlich Frage, ist Immernoch warum funktioniert es im Tutorial reibungslos und warum gibt's beim Debuggen das Problem des nicht vollständig initialisieren graphics Objekts nicht :)

Ansonsten geb ich dann nach meinen versuchen mal Rückmeldung ;)
 
Zuletzt bearbeitet:

Thallius

Top Contributor
Da es sich um zwei Task handeld ist es wahrscheinlich eine timing Sache ob es klappt oder nicht. Beim Debuggen wird wahrscheinlich der UI Task schon fertig sein bevor die GameLoop anläuft.

Gruß

Claus
 

kaoZ

Top Contributor
Ich hab jetzt mal spaßeshalber zum testen folgendes gemacht :

Java:
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable {
    private static final long serialVersionUID = 1L;
    
    
    //pos
    int x = 10;
    int y = 10;
    
    //properties
	static final int WIDTH	 = 320;
	static final int HEIGHT	 = 240;
	static final int SCALE	 = 2;
	
	//gameloop
	Thread thread;
	boolean running;
	static int FPS = 60;
	
	//background
	Background image;
	
	public GamePanel() {
		setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
		setFocusable(true);
		requestFocus();
		
		image = new Background("/background/background.png");
		
		running = true;
	}
	
	private void update()	{
		
		image.update();
	}
	private void render()	{
		
		image.render();
	}
	private void draw()		{
		
		Graphics g = null;
		
		try {
	        g = this.getGraphics();
	        
	        image.draw(g);
        } catch (Exception e) {
	        e.printStackTrace();
        } 
		finally {
        	g.dispose();
        }
	}
	
	@Override
	public void addNotify(){
		super.addNotify();
		
		if(thread == null){
			thread = new Thread(this);
			thread.start();
		}
	}
	
	
	@Override
	public void run() {
	    
		while (running) {
	        
			update();
			render();
			draw();
			
			try {
	            Thread.sleep(100);
            } catch (Exception e) {
	            // TODO: handle exception
            }
        }
	}
}

hier die Klasse Background ( nicht fertig )

Java:
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;

public class Background {
	
	BufferedImage image;
	
	public Background(String path) {
	   try {
	    image = ImageIO.read(getClass().getResourceAsStream(path));
    } catch (Exception e) {
    	e.printStackTrace();
    	}
    }
	
	public void update()	{}
	public void render()	{}
	
	
	public void draw(Graphics g){
		g.drawImage(image, 0, 0, GamePanel.WIDTH, GamePanel.HEIGHT, null);
	}

}

und der Aufruf :

Java:
public class Game {

	public static void main(String[] args) {
	    JFrame f = new JFrame("GameTest");
	    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
	    
	    GamePanel gamePanel = new GamePanel();
	    
	    
	    f.add(gamePanel);
	    f.pack();
	    f.setLocationRelativeTo(null);
	    f.setVisible(true);
    }
	
}

und siehe da keine NPE mehr....., es scheint also tatsächlich an dem vorher noch nicht initialisierten Graphics Objekt es Jpanels, ich habe auch mal das erzeugen des Threads wie im Tutorial in die addNotify() Methode ausgelagert, die so wie auch paintComponent() von Swing / System. selbstständig ausgeführt wird.

nun könnte ich ja Theoretisch hergehen und den Loop noch in eine eigene Klasse auslagern, diesem dann nur das Runnable übergeben, und den panel Referenzieren anstatt von JPanel abzuleiten, oder wie würdet ihr an die Sache herangehen ? , direkt nach dem MVC Pattern umsetzen ? Möchte es anfangs auch nicht zu unübersichtlich gestalten.

[EDIT]Allerdings fliegt nach schließen des Frames noch eine / mehrere NPE's da der GameLoop noch versucht die update/render/draw methoden aufzurufen das Graphics object aber wieder == null ist[/EDIT]
 
Zuletzt bearbeitet:

kaoZ

Top Contributor
So ich habs so wie es aussieht, ich schreibe den Code nochmal um morgen früh und poste einfach mal das Ergebnis falls es wen interessiert ^^
 

kaoZ

Top Contributor
So schauts zzt. aus , ich probiere aber auch noch rum, ich hab nun auch nachvollziehen können warum hier der Thread in einer überschriebenen addNotify() Methode erzeugt wird, da diese standardmäßig vom toolkit aufgerufen wird und hier auch gleich der Listener gesetzt wird.

Da hier liefert mir eine einfach Scroll-Animation mit einem hochskallierten Hintergrund, ich fuchse mich langsam rein, und hab es einfach mal stellenweise kommentiert um den Ablauf nochmal besser nachvollziehen zu können.

Das Problem das beim beenden der Thread noch läuft und drawToScreen() called, obwohl schon kein Graphics objekt mehr da ist, besteht allerdings weiterhin , ich werd wohl noch etwas tüfteln / optimieren / refactoren ;)


Java:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable {
    private static final long serialVersionUID = 1L;
    
    
    //pos
    int x = 10;
    int y = 10;
    
    //properties
	static final int WIDTH	 = 320;
	static final int HEIGHT	 = 240;
	static final int SCALE	 = 2;
	
	//gameloop
	Thread thread;
	boolean running;
	static int FPS = 60;
	
	//rendergraphics
	Graphics renderObject;
	
	//background
	BufferedImage image;
	
	//test
	Background b;
	
	public GamePanel() {
		setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
		setFocusable(true);
		requestFocus();
		
		//rendertest
		////////////////////////////////////////////////////////
		b = new Background("/background/background.png", 1);
		b.setVector(-0.1, 0);
		
		///////////////////////////////////////////////////////
		
	}
	
	private void init(){
		
		image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
		
		running = true;
	}
	
	private void update()	{
		
		b.update();
		
	}
	private void draw()		{

		//get graphics object from empty BufferedImage
		renderObject = image.getGraphics();
		//draw background to BufferedImage
		b.draw(renderObject);
		
	}
	
	private void drawToScreen()		{
		
		Graphics g = null;
		
		try {
	        g = this.getGraphics();
	        //draw Bufferedimage ( rendered + scaled ) to screen(Jpanel)
	        g.drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);   
        } catch (Exception e) {
	        e.printStackTrace();
        } 
		finally {
        	g.dispose();
        }
	}
	
	
	//called by toolkit , addListener / create Thread
	@Override
	public void addNotify(){
		super.addNotify();
		
		if(thread == null){
			thread = new Thread(this);
			addKeyListener(new GameListener());
			thread.start();
		}
	}
	
	
	@Override
	public void run() {
		
		init();
	    
		while (running) {
	        
			update();
			draw();
			drawToScreen();
			
			try {
	            Thread.sleep(10);
            } catch (Exception e) {
	            e.printStackTrace();
            }
        }
	}
	
	class GameListener extends KeyAdapter{

		@Override
        public void keyPressed(KeyEvent e) {
	        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
	        	
            }
	        if (e.getKeyCode() == KeyEvent.VK_LEFT) {
	        	
            }  
        }
	}
}
 
Zuletzt bearbeitet:

Thallius

Top Contributor
Ist es eigentlich so abwegig in Java einfach ein

Java:
g = this.getGraphics();
if(g!=null)
{
    g.drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
}

zu machen um eine Exception zu vermeiden?

Gruß

Claus
 

kaoZ

Top Contributor
Nein natürlich nicht, nur da ich vorher schon Probleme hatte herauszufinden wo genau die NPE auftritt, ist es einfacher dies mit stacktrace herauszufinden als wenn einfach nichts passiert ;)

Das ist hier auch lange noch keine finale Version^^ es ging erst einmal darum zu vermeiden das hier der EDT startet bevor der gameloop / Thread läuft und eben das Graphics Objekt noch nicht vollständig initialisiert ist.

Mal davon abgesehen ist es
a) keine Ausnahmebehandlung hier nur den Stack ausgeben zu lassen, und
b) viel zu allgemein hier nur Exceptions abzufangen :)
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
S Graphics Objekt weiterreichen? Spiele- und Multimedia-Programmierung 4
G Einen gif oder jpg Datei aus einem Graphics Objekt o. JFrame Spiele- und Multimedia-Programmierung 2
K Hashmap mit 2D Graphics Spiele- und Multimedia-Programmierung 7
FunnyO Graphics fillOval weiche Kanten Spiele- und Multimedia-Programmierung 8
Steev Eigener Graphics-Context Spiele- und Multimedia-Programmierung 10
S Graphics.drawString (Graphics2D.drawString) Y-Problem Spiele- und Multimedia-Programmierung 4
G Wie bekomme ich einen Punkt (Graphics) Spiele- und Multimedia-Programmierung 2
K stringWidth bei Graphics von JPanel und Printer unterschiedl Spiele- und Multimedia-Programmierung 4
P Graphics Klasse Spiele- und Multimedia-Programmierung 3
N Performance Problem bei mit Graphics Spiele- und Multimedia-Programmierung 6
V Graphics oder Graphics2D Zeichenfunktion gesucht? Spiele- und Multimedia-Programmierung 4
O transparente farbe in Image mit Graphics Spiele- und Multimedia-Programmierung 8
G Graphics bei Java aufteilen Spiele- und Multimedia-Programmierung 3
C Graphics 2D Zeichnen Spiele- und Multimedia-Programmierung 4
F einzelne Polygone(Graphics) schneller als and. Fig. zeichnen Spiele- und Multimedia-Programmierung 3
pcfreak9000 Objekt-Vorlagen Spiele- und Multimedia-Programmierung 0
Arif Maus-Objekt im Player Klasse implementieren !? Spiele- und Multimedia-Programmierung 2
H Objekt der Klasse A in der Klasse B verwenden und manipulieren Spiele- und Multimedia-Programmierung 6
M [JOGL] Maus über einem gezeichnetem Objekt abfragen? Spiele- und Multimedia-Programmierung 5
U Kann nur ein Objekt mit LWJGL rendern Spiele- und Multimedia-Programmierung 2
E Java3D Objekt skalieren per JSlider/JButton Spiele- und Multimedia-Programmierung 10
D Probleme mit objekt initializirung mit Mouselistener Spiele- und Multimedia-Programmierung 10
S Java3D: Primitives zu einem Objekt kombinieren Spiele- und Multimedia-Programmierung 7
T LWJGL 3D Objekt Collision: Wie? Spiele- und Multimedia-Programmierung 11
S Wie erkennt ein Objekt ein anderes? Spiele- und Multimedia-Programmierung 7
B j3d mehr als ein Objekt rotieren Spiele- und Multimedia-Programmierung 18
G Hindernis vor Objekt erkennen Spiele- und Multimedia-Programmierung 6
W Java3D: Kanten die hinter einem Objekt liegen werden gezeigt Spiele- und Multimedia-Programmierung 2
H Eigenes 3D Objekt Spiele- und Multimedia-Programmierung 20
D 2D Objekt fragmentieren Spiele- und Multimedia-Programmierung 3
V Jogl: Objekt trotz Rotation immer in gleiche Richtung bewegen Spiele- und Multimedia-Programmierung 5
M [J3D]Dynamische Erzeugung vom Objekt Box Spiele- und Multimedia-Programmierung 5
Kr0e OpenGL .. Pixel Buffer Objekt oder Frame Buffer Object? Spiele- und Multimedia-Programmierung 2
B String zu Objekt einer eigenen Klasse casten Spiele- und Multimedia-Programmierung 13
N Objekt entgegengesetzt bewegen Spiele- und Multimedia-Programmierung 8
M BoundingBox ist nicht bündig am Objekt Spiele- und Multimedia-Programmierung 5
K Kanten anzeigen lassen in einem Shape3D-Objekt Spiele- und Multimedia-Programmierung 4
S geladenes Objekt -> Material Zuweisen. Spiele- und Multimedia-Programmierung 4
J Picking Selection auf ein Objekt begrenzen ! Spiele- und Multimedia-Programmierung 6
C Objekt bei Buttonklick zeichnen Spiele- und Multimedia-Programmierung 16
G JOGL: per Mausbewegung Objekt verschieben Spiele- und Multimedia-Programmierung 2
C Objekt zwischen 2 Geraden? Spiele- und Multimedia-Programmierung 3
D 3D Objekt entlang Geraden Spiele- und Multimedia-Programmierung 4
Quaxli Picking: Vom Shape3D zum eigentlichen Objekt Spiele- und Multimedia-Programmierung 2
G Objekt nicht ins negative oder null skalieren Spiele- und Multimedia-Programmierung 2
G Objekt verschieben Spiele- und Multimedia-Programmierung 6
G Textur laden auf ein eingelesenes 3D Objekt Spiele- und Multimedia-Programmierung 4
I ScaleInterpolator verschiebt Objekt immer in den Ursprung. Spiele- und Multimedia-Programmierung 2
V Objekt per Tastendruck anzeigen/verschwinden lassen? Spiele- und Multimedia-Programmierung 4
R Objekt mit cos/sin verschieben Spiele- und Multimedia-Programmierung 27
G Kein Licht in Box-Objekt Spiele- und Multimedia-Programmierung 2
K Ein 3D-Objekt mit Maus auswählen Spiele- und Multimedia-Programmierung 5
D Alpha Objekt Spiele- und Multimedia-Programmierung 8
H Kompliziertes 3D-Objekt Spiele- und Multimedia-Programmierung 16
C Wie kann ich ein Objekt auf Tastendruck vor & zurück bew Spiele- und Multimedia-Programmierung 3
M Position der ViewingPlatform als Point3d-Objekt? Spiele- und Multimedia-Programmierung 12
S 3D Objekt erstellen und darstellen Spiele- und Multimedia-Programmierung 4
G RotationInterp. setzt Objekt an Ursprungsposition zurück Spiele- und Multimedia-Programmierung 2
N Shape3D Objekt auf dem Bildschirm zentrieren Spiele- und Multimedia-Programmierung 2
F HashMap liefert nicht gewünschten Wert (gar nix) Spiele- und Multimedia-Programmierung 5
F getRGB liefert andere Werte als PS? Spiele- und Multimedia-Programmierung 8

Ähnliche Java Themen

Neue Themen


Oben