Image == null, DrawImage

Hey Leute ich versuche gerade etwas einfaches in ein JFrame zu zeichnen.
Ich möchte gerne Rechtecke einfärben und einfach in das JFrame zeichnen.
Jedoch sagt er mir das das Image null ist.

import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.JFrame;

public class DrawMap extends JFrame {

	private static final long serialVersionUID = -704622269030243330L;
	private Graphics graphic;
	private Image image;

	public DrawMap() {
	
		
		image = this.createImage(400,400);
		System.out.println(image);
		graphic = image.getGraphics();
		setSize(400, 400);
		setVisible(true);
		graphic.setColor(Color.BLACK);
		graphic.fillRect(20, 20, 20, 20);
        graphic.drawImage(image,0,0,null);
	}

}

ein JFrame ohne setVisible(true) oder eine sonstige Komponente nirgendwo eingefügt ist nur die Hälfte wert,
kein Umgebungskontext, keine Anbindung an Systemressourcen zum Zeichnen

nach setVisible(true) gehts, aber bleibt eher unschöner Blackbox-Weg,
wie wärs mit einem selber erstellten BufferedImage?
https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html

Ok und wieso zeichnet er mir jetzt kein Rechteck auf das JFrame :o?

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

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

public class DrawMap extends JFrame {

	private static final long serialVersionUID = -704622269030243330L;
	private Graphics graphic;
	private BufferedImage image = new BufferedImage(400, 400,
			BufferedImage.TYPE_INT_ARGB);

	public DrawMap() {
		setSize(400, 400);
		setVisible(true);
		graphic = image.getGraphics();
		graphic.setColor(Color.YELLOW);
		graphic.fillRect(0, 0, 50, 100);

		JPanel panel = new JPanel();
		add(panel);
		panel.getGraphics().drawImage(image, 0, 0, this);

	}

}

so malt man nicht, kein grundsätzliches Tutorial zu Malen in Swing bekannt,
vor komplizierten eigenen Image-Objekten simple Striche malen?

wobei dass gelbe Dreieck ja dafür/ dagegen spricht, je nachdem wie den Satz gedreht,
Malen nur in überschriebener paintComponent!


und nachträglich hinzugefügte Komponenten erst etwas kompliziert ins Layout neu einzurichten (revalidate evtl.)

vielleicht besser soweit möglich beim Grundsatz bleiben, alle Komponenten vor setVisible(true) einzufügen,
dann mit if darauf reagieren ob Bild da oder nicht

beim späteren Hinzufügen des Bildes freilich repaint() immer noch nötig, aber der Befehl ist recht normal

        JPanel panel = new JPanel()    {

                @Override
                protected void paintComponent(Graphics g)   {
                    super.paintComponent(g);
                    if (image != null) g.drawImage(image, 0, 0, this);
                }
            };
        add(panel);

        setSize(400, 400);
        setVisible(true);

        graphic = image.getGraphics();
        graphic.setColor(Color.YELLOW);
        graphic.fillRect(0, 0, 50, 100);

        repaint(); // alleine reagiert das JFrame nicht auf das neue image, mit dem Aufruf alles neu zeichnen
    }

edit: wobei ja nun das Bild unabhängig ist, könnte nun auch ganz am Anfang vor dem JFrame bemalt werden,
dann sofort richtig dargestellt,
und das if (image != null) unnötig, ich war noch dabei dass das image erst später hinzukommt

Würde noch hinzufügen das die zu überschreibende Methode

„paintComponent()“ heißt /!\ und nicht „paintComponents()“ oder nur „paint()“ oder was da noch so an ähnlichen Methodennamen herumstreunt.
Verwechslungen gabs schon haufenweise deswegen und meist funktioniert dann irgendwas nicht.

Außerdem muss strikt /!
„super.paintComponent(Graphics g);“
aufgerufen werden. Auch ganz ganz wichtig!
Es ist einfach einen Fehler im Code zu finden, aber es ist sau schwer einen Fehler zu finden der NICHT im Code ist.

Wollte das nur nochmal hervorheben, dann erspart man sich unnötig Ärger und Fehlersucherei.

Dieses (Malen in AWT und Swing) und weitere Turorials zum Zeichnen in Swing findest du bei uns im Byte-Welt-Wiki.