# Paint Methode von JPanel aufrufen



## javabeginner21 (19. Sep 2011)

Hallo,

ich habe vor in einer Klasse (SpielFeld) ein Raster von mehreren Quadraten zu erzeugen. Diese Quadrate sollen alle zu beginn das selbe Bild zeigen. Bis jetzt habe ich folgendes geschrieben:

```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.util.ArrayList;
import java.util.Random;
import java.awt.color.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.*;


public class SpielFeld extends JFrame{
	
	JPanel hauptPanel;
	JFrame hauptFenster;
	
	int spalte=20;
	int zeile=20;
	int schiffe=3;
	int felder=spalte+zeile;
		
	Image[] bilder;
	int bilderAnzahl=3;
	BufferedReader bilderLeser;
		
	
	Bild bild;
	
	
		
public static void main(String[] args){
	SpielFeld spiel = new SpielFeld();
	spiel.neuesSpiel();
	
}

public void neuesSpiel(){
	
	bilder = new Image[bilderAnzahl];
	
	//Fenster erzeugen
	hauptFenster = new JFrame("Schiffe versenken");
	hauptFenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	hauptFenster.setVisible(true);
	hauptFenster.setSize(420, 450);
	hauptFenster.setLocationRelativeTo(null);
	
	
	
	
	//Bilder einlesen
	
	test =(new ImageIcon(this.getClass().getResource("1.png"))).getImage();
	bild = new Bild();
	hauptPanel = new JPanel();
	hauptFenster.add(BorderLayout.CENTER, hauptPanel);
	JButton button = new JButton("test");
	hauptPanel.add(bild);
	
	
	
	}
	

	
@Override public void paint(Graphics g){
	
	System.out.println("paint Hauptklasse");
}
	
	class Bild extends JPanel {
		
		public void paintComponent(Graphics g){
			System.out.println("paintComponent");
		}
			
		public void paint(Graphics g){
			System.out.println("paint");
			//g.drawImage(test,20,20,this);
			g.setColor(Color.blue);
			g.fillRect(10, 10, 30, 40);
				
		}
	}
		
}
```
 
Mein Problem ist, dass ich Gerne zu beginn in dem JFrame das JPanel mit den Bildern zeichnen möchte. Später soll das ganze erweitert werden und mit einem MouseListener per Mausklick die Bilder auf dem JPanel sich ändern. Wie steuere ich genau wann paint aufgerufen wird und das es auch wirklich auf dem JPanel gezeichnet wird. Muss dazu das JFrame auch refreshed werden? Habe schon einiges gelesen, steige aber leider nicht so ganz dahinter. Danke schonmal für eure Hilfe.


----------



## Marco13 (19. Sep 2011)

Auf jeden Fall solltest du nicht die paint-Methode des Frames überschreiben (oder wenn, dann zumindest
super.paint(g);
als erste Zeile aufrufen). Vielleicht hilft ja schon ein bißchen das (noch entstehende) http://www.java-forum.org/entwuerfe/113007-kein-swing-tutorial-2.html#post806478


----------



## javabeginner21 (19. Sep 2011)

Habe die paint Methode des Frames rausgenommen. Ich verstehe nur nicht wieso nur das Frame auf geht allerdings nicht die paint Methode von der inneren Klasse Bild aufgerufen wird. Was mache ich da falsch? Oder ist das Grundsätzlich ein schlechter ansatz wie ich es mache?


----------



## Michael... (19. Sep 2011)

javabeginner21 hat gesagt.:


> Oder ist das Grundsätzlich ein schlechter ansatz wie ich es mache?


Ich würde mir - vor allem als Anfänger - angewöhnen bei Swing Komponenten wie Deinem JPanel ausschließlich die 
	
	
	
	





```
paintComponent(Graphics g)
```
 zu überschreiben und darin als erstes 
	
	
	
	





```
super.paintComponent(g)
```
 aufzurufen.
Dass nichts zu sehen ist, liegt daran, dass Deine Komponente "Bild" ein Größe von 0x0 besitzt. Dein JPanel 
	
	
	
	





```
hauptPanel
```
 verwendet default ein FlowLayout, das sich an der 
	
	
	
	





```
PreferredSize
```
 der Komponenten orientiert.
Entweder der Komponente eine Größe zuweisen, oder - da das vermutlich ein Memory oder ähnliches werden soll - dem hauptPanel ein GridLayout  mit dem entsprechenden Raster zu weisen.


----------



## Marco13 (19. Sep 2011)

Oh ja, bei der Klasse hast du auch paint überschrieben. Auch dort sollte ggf. ein super.paint(g) drin stehen, aber besser ist, was Michael... schon gesagt hat: NUR die paintComponent überschreiben (und da drin ein super.paintComponent(g) als erste Zeile). Schau dir auch mal der verlinkte Beispiel an.


----------



## javabeginner21 (19. Sep 2011)

also erst mal danke. Habe es jetzt so abgeändert, dass ich nur noch ein JPanel habe. Soweit funktioniert es. Allerdings habe ich noch Fragen. Es wird immer nur die Paint Methode aufgerufen und nicht die PaintComponent. Warum? Außerdem habe ich mit Eclipse das Problem das beim ausführen des Codes mal die paint Methode aufgerufen wird und mal nicht. so ca. jedes zweite mal wenn ich den Code ausführe. Das dasrf doch nicht sein. Weiß jemand von euch vielleicht woran das liegen könnte. Ziemlich merkwürdig.


```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.util.ArrayList;
import java.util.Random;
import java.awt.color.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.*;


public class SpielFeld{
	
	JFrame hauptFenster;
	
	int spalte=20;
	int zeile=20;
	int schiffe=3;
	int felder=spalte+zeile;
		
	Image[] bilder;
	int bilderAnzahl=3;
	BufferedReader bilderLeser;
		
	Image test;
	Bild bild;
	
	
		
public static void main(String[] args){
	SpielFeld spiel = new SpielFeld();
	spiel.neuesSpiel();
	
}

public void neuesSpiel(){
	
	bilder = new Image[bilderAnzahl];
	
	//Fenster erzeugen
	hauptFenster = new JFrame("Schiffe versenken");
	hauptFenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	hauptFenster.setVisible(true);
	hauptFenster.setSize(420, 450);
	hauptFenster.setLocationRelativeTo(null);
	hauptFenster.setLayout(new BorderLayout());
	
	
	
	//Bilder einlesen
	test =(new ImageIcon(this.getClass().getResource("1.png"))).getImage();
	bild = new Bild();
	hauptFenster.getContentPane().add(BorderLayout.CENTER, bild);
	
		
	}
	
	class Bild extends JPanel {
		
	@Override public void paintComponent(Graphics g){
		super.paint(g);	
		System.out.println("paintComponent");
		}
		
		
		@Override public void paint(Graphics g){
			super.paintComponent(g);
			System.out.println("paint");
			g.drawImage(test,20,20,this);
			//g.setColor(Color.blue);
			//g.fillRect(10, 10, 30, 40);
			
			
		}
	}
	
		
}
```


----------



## njans (19. Sep 2011)

Öhm wieso rufst du in der Paint() die paintComponent() auf udn umgekehrt? 
Das macht so wenig Sinn  
Sorge mal dafür, dass der super Aufruf immer nur die Methode aufruft in der er auch steht.


----------



## André Uhres (19. Sep 2011)

Hallo javabeginner21,

herzlich willkommen bei java-forum.org .

Versuch's mal so:

```
import java.awt.*;
import javax.swing.*;
public class SpielFeld {
    private JFrame hauptFenster;
    private Image test;
    private Bild bild;
    public static void main(final String[] args) {
        Runnable gui = new Runnable() {
            @Override
            public void run() {
                SpielFeld spiel = new SpielFeld();
                spiel.neuesSpiel();
            }
        };
        //GUI must start on EventDispatchThread:
        SwingUtilities.invokeLater(gui);
    }
    public void neuesSpiel() {
        //Fenster erzeugen
        hauptFenster = new JFrame("Schiffe versenken");
        hauptFenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        hauptFenster.setSize(420, 450);
        hauptFenster.setLocationRelativeTo(null);
        hauptFenster.setLayout(new BorderLayout());
        //Bilder einlesen
        test = (new ImageIcon(this.getClass().getResource("1.png"))).getImage();
        bild = new Bild();
        hauptFenster.getContentPane().add(BorderLayout.CENTER, bild);
        hauptFenster.setVisible(true);
    }
    private class Bild extends JPanel {
        @Override
        public void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.drawImage(test, 20, 20, this);
        }
    }
}
```
Gruß,
André


----------



## javabeginner21 (19. Sep 2011)

Danke für den Hinweis. Hatte mich da vertan. Sollte eigentlich auch so sein wie du geschrieben hast. Verstehe im Moment nur nicht warum erst nach mehrmaligen ausführen des Programmes aus Eclipse der paintComponent aufruf funktioniert. Sehr sehr seltsam. Bin für jeden Tipp dankbar.


----------



## javabeginner21 (19. Sep 2011)

Danke, sorry hatte deine Antwort nicht gelesen@André Uhres
Jetzt geht es, nachdem die Sichtbarkeit des Fensters später im code steht.


----------



## javabeginner21 (26. Sep 2011)

Hallo,

sorry das ich deswegen nochmals anfrage. Habe mit dem paintComponent noch Probleme. Und zwar 
wird das paintComponent mehrfach aufgerufen. Leider habe ich nicht herausgefunden wieso. In dem Code wird eine zweite Klasse namens Fenster aufgerufen. Diese erstellt im Konstruktor nur ein normales Fenster. Danach wird ein Panel erstellt und dem Fenster hinzugefügt. Was mache ich nur falsch.


```
package NeueVersion;

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class SpielFeld {

	int zeilen=10;
	int zeilengröße = 20;
	int spalten=10;
	int spaltengröße=20;
	int[] feld= new int[zeilen*spalten];
	
	boolean neuesSpiel=true;
	
	int bilderAnzahl =3;
	Image[] image = new Image[bilderAnzahl];
	
	
	
	
	
	
	public static void main(String[] args) {
		SpielFeld spiel = new SpielFeld();
		spiel.start();

	}
	
	public void start(){
		
		//Bilder einlesen
		for(int i=0;i<bilderAnzahl;i++){
		image[i] = (new ImageIcon(this.getClass().getResource((i)+ ".png"))).getImage();
		}
		
		//Fenster erstellen
		Fenster frame = new Fenster();
		
		Panel panel = new Panel();
		
		panel.addMouseListener(new MausListener());
		
		frame.add(panel, BorderLayout.CENTER);
		
		
		
		
		
		
		
	}
	public class Panel extends JPanel{
		
		int zelle =0;
		
		public void paintComponent(Graphics g){
			super.paintComponent(g);
			System.out.println("neuesSpiel: "+neuesSpiel);
			if ( neuesSpiel == true){
				for (int i = 0; i< zeilen;i++ ){
					for (int j = 0; j< spalten;j++){
				//zelle = feld[(i*spalten)+j];
						g.drawImage(image[0], (i * zeilengröße), (j * spaltengröße), this);
					
					}
				}
			
			neuesSpiel = false;
			}
			
			System.out.println("paintComponent ");
			
			
			
			
		}
	}
	
	public class MausListener implements MouseListener{

		public void mouseClicked(MouseEvent arg0) {
			int x = arg0.getX();
			int y = arg0.getY();
			
			int aktuelleZeile = y /  zeilengröße;
			int aktuelleSpalte = x / spaltengröße;
			
			//System.out.println("x:"+x+" y:"+y );
			System.out.println("aktuelleZeile:"+aktuelleZeile+" aktuelleSpalte:"+aktuelleSpalte);
			
			
			
		}

		public void mouseEntered(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		public void mouseExited(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		public void mousePressed(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		public void mouseReleased(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}
		
	}
	
}
```


----------



## Marco13 (26. Sep 2011)

Dass die paintComponent "oft" aufgerufen wird, ist normal. Wenn sich die Fenstergröße ändert, wenn das Fenster kurz verdeckt war, wenn irgendwoher ein repaint() aufgerufen wurde. Solange in der paintComponent NUR gezeichnet wird, sollte das kein Problem sein. Das "neuesSpiel" sollte also NICHT in der paintComponent verändert werden.


----------



## Gast2 (26. Sep 2011)

Nur ne kleine Anmerkung:

```
public class Panel extends JPanel{
```
Klassen sollte man nie so nennen wie Klassen aus der Standard-API.


----------



## javabeginner21 (29. Sep 2011)

Danke für eure Hilfe.


----------



## Exflame (1. Okt 2011)

Kann ich in der Paint-Methode auch den gewünschten Panel angeben? Ich hab hier ein Programm, das aus 6 div. Panels besteht. Auf vier Panels muss ich je eine andere Grafik erstellen (Sinus,....). :autsch:


----------



## Marco13 (1. Okt 2011)

Ein eigener Thread, idealerweise mit KSKB, würde sicher schneller zu Ergebnsisen führen.


----------

