Methoden "Non-static method xy cannot be referenced from a static context"

muff-in

Mitglied
Hallo,

Beim übersetzen meiner Klasse taucht diese Fehlermeldung auf.
Ich habe sehr lange gegoogelt und auch hier im Forum gesucht, und ich weiß dass dieser Fehler schon öfters besprochen wurde, aber leider kann ich die Lösungsvorschläge irgendwie nicht umsetzen.;(

Ich arbeite mit BlueJ und versuche TickTackToe zu programmieren. 😀
Dabei geht es um meine Klasse Spielfeld.
In dieser Klasse gibt es, nach dem Konstruktor, eine Methode "zeichneSpielbrett()" und in der wird mithilfe einer forSchleife mehrere Objekte der Klasse "Kreis" erzeugt und in einem Feld namens "Kreisparameter[]" abgespeichert.
Das alles funktioniert einwandfrei.

In der 2. Methode zeichneSpielstein() will ich jetzt auf ein beliebiges Objekt in dem Feld "Kreisparameter[]" zugreifen, und von diesem Objekt die Farbe verändern.
Ich will kein neues Objekt erzeugen. Und genau hier taucht immer wieder der Fehler auf.;(

Ich kopier euch die jeweiligen Quelltexte rein, meine Klasse Spielfeld habe ich extrem gekürzt, auch die Klasse Kreis.
Klasse Leinwand habe ich fast so gelassen wie sie ist.

Hier ist der Quelltext der Klasse Spielfeld:

Java:
public class Spielfeld 
{
    Kreis[] kreisparameter      = new Kreis[9];

    public Spielfeld() 
    { }

    public void zeichneSpielbrett(){
        
// Diese forSchleife wurde SEHR VIEL gekürzt (ich hab alle Parameter und die ineinander geschachtelten forSchleifen rausgeschmissen wegen der Überschaubarkeit) funktioniert normalerweise einwandfrei.
            for (int q=0; q<3; q++){  
              kreisparameter[f] = new Kreis(g,ax,bx,a);
        }

    public void zeichneSpielstein(int feldnummer, int spieler){
 // Hier ist der Fehler: hab alles möglich durchprobiert von this.farbeAendern("") bis alles Static deklarieren .. nix geht.
             kreisparameter[feldnummer] = Kreis.farbeAendern("gruen");
        }

Quelltext der Klasse Kreis

Java:
import java.awt.geom.Ellipse2D;

public class Kreis {
	private int durchmesser;
	private int xPosition;
	private int yPosition;
	private String farbe;
	private boolean istSichtbar;
	
       public Kreis(int d, int x, int y, String f) {
		durchmesser = d;
		xPosition = x;
		yPosition = y;
		farbe = f;
		istSichtbar = false;
		sichtbarMachen();
	}


	public void sichtbarMachen() {
		istSichtbar = true;
		zeichnen();
	}


	/**
	 * Ändere die Farbe dieses Kreises in 'neueFarbe'. Gültige Angaben sind
	 * "rot", "gelb", "blau", "gruen", "lila" und "schwarz".
	 */
	public void farbeAendern(String neueFarbe) {
		farbe = neueFarbe;
		zeichnen();
	}

	/**
	 * Zeichne diesen Kreis mit seinen aktuellen Werten auf den Bildschirm.
	 */
	private void zeichnen() {
		if (istSichtbar) {
			Leinwand leinwand = Leinwand.gibLeinwand();
			leinwand.zeichne(this, farbe, new Ellipse2D.Double(xPosition,
					yPosition, durchmesser, durchmesser));
			leinwand.warte(10);
		}
	}

}

Quelltext der Klasse Leinwand:

Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

/**
 * Leinwand ist eine Klasse, die einfache Zeichenoperationen auf einer
 * leinwandartigen Zeichenfläche ermöglicht. Sie ist eine vereinfachte Version
 * der Klasse Canvas (englisch für Leinwand) des JDK und wurde speziell für das
 * Projekt "Figuren" geschrieben.
 * 
 * 
 * @author: Bruce Quig
 * @author: Michael Kölling (mik)
 * @author: Axel Schmolitzky
 * 
 * @version: 2006.03.30
 */
public class Leinwand {
	// Hinweis: Die Implementierung dieser Klasse (insbesondere die
	// Verwaltung der Farben und Identitäten der Figuren) ist etwas
	// komplizierter als notwendig. Dies ist absichtlich so, weil damit
	// die Schnittstellen und Exemplarvariablen der Figuren-Klassen
	// für den Lernanspruch dieses Projekts einfacher und klarer
	// sein können.

	private static Leinwand leinwandSingleton;

	/**
	 * Fabrikmethode, die eine Referenz auf das einzige Exemplar dieser Klasse
	 * zurückliefert. Wenn es von einer Klasse nur genau ein Exemplar gibt, wird
	 * dieses als 'Singleton' bezeichnet.
	 */
	public static Leinwand gibLeinwand() {
		if (leinwandSingleton == null) {
			leinwandSingleton = new Leinwand("BlueJ Figuren Demo", 300, 300,
					Color.white);
		}
		leinwandSingleton.setzeSichtbarkeit(true);
		return leinwandSingleton;
	}

	// ----- Exemplarvariablen -----

	private JFrame fenster;

	private Zeichenflaeche zeichenflaeche;

	private Graphics2D graphic;

	private Color hintergrundfarbe;

	private Image leinwandImage;

	private List<Object> figuren;

	private Map<Object, ShapeMitFarbe> figurZuShape;
	
	/**
	 * Erzeuge eine Leinwand.
	 * 
	 * @param titel
	 *            Titel, der im Rahmen der Leinwand angezeigt wird
	 * @param breite
	 *            die gewünschte Breite der Leinwand
	 * @param hoehe
	 *            die gewünschte Höhe der Leinwand
	 * @param grundfarbe
	 *            die Hintergrundfarbe der Leinwand
	 */
	private Leinwand(String titel, int breite, int hoehe, Color grundfarbe) {
		fenster = new JFrame();
		zeichenflaeche = new Zeichenflaeche();
		fenster.setContentPane(zeichenflaeche);
		fenster.setTitle(titel);
		zeichenflaeche.setPreferredSize(new Dimension(breite, hoehe));
		hintergrundfarbe = grundfarbe;
		fenster.pack();
		figuren = new ArrayList<Object>();
		figurZuShape = new HashMap<Object, ShapeMitFarbe>();
	}

	/**
	 * Setze, ob diese Leinwand sichtbar sein soll oder nicht. Wenn die Leinwand
	 * sichtbar gemacht wird, wird ihr Fenster in den Vordergrund geholt. Diese
	 * Operation kann auch benutzt werden, um ein bereits sichtbares
	 * Leinwandfenster in den Vordergrund (vor andere Fenster) zu holen.
	 * 
	 * @param sichtbar
	 *            boolean für die gewünschte Sichtbarkeit: true für sichtbar,
	 *            false für nicht sichtbar.
	 */
	public void setzeSichtbarkeit(boolean sichtbar) {
		if (graphic == null) {
			// erstmaliger Aufruf: erzeuge das Bildschirm-Image und fülle
			// es mit der Hintergrundfarbe
			Dimension size = zeichenflaeche.getSize();
			leinwandImage = zeichenflaeche.createImage(size.width, size.height);
			graphic = (Graphics2D) leinwandImage.getGraphics();
			graphic.setColor(hintergrundfarbe);
			graphic.fillRect(0, 0, size.width, size.height);
			graphic.setColor(Color.black);
		}
		fenster.setVisible(sichtbar);
	}

	/**
	 * Zeichne für das gegebene Figur-Objekt eine Java-Figur (einen Shape) auf
	 * die Leinwand.
	 * 
	 * @param figur
	 *            das Figur-Objekt, für das ein Shape gezeichnet werden soll
	 * @param farbe
	 *            die Farbe der Figur
	 * @param shape
	 *            ein Objekt der Klasse Shape, das tatsächlich gezeichnet wird
	 */
	public void zeichne(Object figur, String farbe, Shape shape) {
		figuren.remove(figur); // entfernen, falls schon eingetragen
		figuren.add(figur); // am Ende hinzufügen
		figurZuShape.put(figur, new ShapeMitFarbe(shape, farbe));
		erneutZeichnen();
	}

	/**
	 * Entferne die gegebene Figur von der Leinwand.
	 * 
	 * @param figur
	 *            die Figur, deren Shape entfernt werden soll
	 */
	public void entferne(Object figur) {
		figuren.remove(figur); // entfernen,falls schon eingetragen
		figurZuShape.remove(figur);
		erneutZeichnen();
	}

	/**
	 * Setze die Zeichenfarbe der Leinwand.
	 * 
	 * @param farbname
	 *            der Name der neuen Zeichenfarbe.
	 */
	public void setzeZeichenfarbe(String farbname) {
		if (farbname.equals("rot")) {
			graphic.setColor(Color.red);
		} else if (farbname.equals("schwarz")) {
			graphic.setColor(Color.black);
		} else if (farbname.equals("blau")) {
			graphic.setColor(Color.blue);
		} else if (farbname.equals("gelb")) {
			graphic.setColor(Color.yellow);
		} else if (farbname.equals("gruen")) {
			graphic.setColor(Color.green);
		} else if (farbname.equals("lila")) {
			graphic.setColor(Color.magenta);
		} else if (farbname.equals("weiss")) {
			graphic.setColor(Color.white);
		} else {
			graphic.setColor(Color.black);
		}
	}

	/**
	 * Warte für die angegebenen Millisekunden. Mit dieser Operation wird eine
	 * Verzögerung definiert, die für animierte Zeichnungen benutzt werden kann.
	 * 
	 * @param millisekunden
	 *            die zu wartenden Millisekunden
	 */
	public void warte(int millisekunden) {
		try {
			Thread.sleep(millisekunden);
		} catch (Exception e) {
			// Exception ignorieren
		}
	}

	/**
	 * Zeichne erneut alle Figuren auf der Leinwand.
	 */
	private void erneutZeichnen() {
		loeschen();
		for (Object figur : figuren) {
			figurZuShape.get(figur).draw(graphic);
		}
		zeichenflaeche.repaint();
	}

	/**
	 * Lösche die gesamte Leinwand.
	 */
	private void loeschen() {
		Color original = graphic.getColor();
		graphic.setColor(hintergrundfarbe);
		Dimension size = zeichenflaeche.getSize();
		graphic.fill(new Rectangle(0, 0, size.width, size.height));
		graphic.setColor(original);
	}

	/***************************************************************************
	 * Interne Klasse Zeichenflaeche - die Klasse für die GUI-Komponente, die
	 * tatsächlich im Leinwand-Fenster angezeigt wird. Diese Klasse definiert
	 * ein JPanel mit der zusätzlichen Möglichkeit, das auf ihm gezeichnet Image
	 * aufzufrischen (erneut zu zeichnen).
	 */
	private class Zeichenflaeche extends JPanel {
		private static final long serialVersionUID = 20060330L;

		public void paint(Graphics g) {
			g.drawImage(leinwandImage, 0, 0, null);
		}
	}

	/***************************************************************************
	 * Interne Klasse ShapeMitFarbe - Da die Klasse Shape des JDK nicht auch
	 * eine Farbe mitverwalten kann, muss mit dieser Klasse die Verknüpfung
	 * modelliert werden.
	 */
	private class ShapeMitFarbe {
		private Shape shape;

		private String farbe;

		public ShapeMitFarbe(Shape shape, String farbe) {
			this.shape = shape;
			this.farbe = farbe;
		}

		public void draw(Graphics2D graphic) {
			setzeZeichenfarbe(farbe);
			graphic.fill(shape);
		}
	}

}
 
Java:
kreisparameter[feldnummer] = Kreis.farbeAendern("gruen");
Du brauchst ein Objekt der Klasse Kreis um die Methode farbeÄndern aufzurufen. Tuts nicht einfach
Java:
kreisparameter[feldnummer].farbeÄndern("gruen");
?

PS:
Vermeide Sonderzeichen und äöü in deinem Quelltext.
 
Gott ich bin so dumm!

Sorry. Aber es funktioniert jetzt =)

Vielen Dank. =)

PS: Aber warum? Die Methode farbeAendern ist doch in der Klasse Kreis drin oder nicht?
Muss ich das denn nicht auch irgendwie angeben?
 
Dein Array kreisparameter ist vom Typ Kreis. Das heißt jedes Objekt dass sich in dem Array befindet hat sicher die Methode farbeÄndern.
 
Startest du das Programm von der main() - Methode ?

[c]public static void main(String[] args) { [/c] ?
 
Nein, ich irgendwie reicht bei BlueJ "public class Spielfeld{ ..." aus.
Wenn das das ist was du meinst. Dann kann man mit der rechten Maustaste das Objekt erzeugen und dann wieder mit rechten Maustaste die Methoden ausführen.

Aber es funktioniert inzwischen schon. =)

Der Fehler war bei "kreisparameter[feldnummer] = Kreis.farbeAendern("gruen")". Das muss zu

Java:
kreisparameter[feldnummer].farbeAendern("gruen");

und dann funktionierts =).
 
Noch eine winzig kleine Frage.

Also es wird einwandfrei Übersetzt aber wenn ich dann das Objekt erzeuge und die Methode aufrufe
kommt:

"java.lang.NullPointerException
at Spielfeld.zeichneSpielstein(Spielfeld.java:56)"


🙁
 
In Spielfeld Zeile 56 ist irgendwas null. Wo genau das bei dir ist kann man aufgrund deines geposteten Codes nicht sagen.

EDIT:
Vermutlich hast du keine Objekte in deinem Array.
 
Das hier ist die Methode

Java:
public void zeichneSpielstein(int feldnummer, int spieler){
        if(spielfeld[feldnummer] == 0){
            spielfeld[feldnummer] = spieler;
            if(spieler == 1) {
// Diese untere Zeile ist die Zeile 56
                kreisparameter[feldnummer].farbeAendern("gruen");
            }else{
                dreieckparameter[feldnummer].farbeAendern("blau");
            }
        }

hm warum wird das null?!

PS: doch, die Methode zeichneSpielbrett habe ich davor ausgeführt.
 
Das hier sind die Methoden zeichneSpielbrett() und zeichneSpielstein().
Und in der Methode zeichneSpielstein() wird die Methode zeichneSpielbrett() automatisch schon aufgerufen.

Java:
public void zeichneSpielbrett(){
        Quadrat hintergrund = new Quadrat(190,0,0,"schwarz");
        
        int g = 50;
        int ax = 10;
        int f=0;
        String a = "rot";

        for(int k=0; k<3; k++){
            int bx = ax + 60*k;
            for (int q=0; q<3; q++){  
                feldparameter[f] = new Quadrat(g,ax,bx,a);
                kreisparameter[f] = new Kreis(g,ax,bx,a);
                dreieckparameter[f] = new Dreieck(g,g,ax+25,bx,a);
                if(ax==10){
                    ax=70;
                }else if(ax==70){
                    ax=130;
                }else if(ax==130){
                    ax=10;
                }
            }
            f++; 
        }
    }
    
    public void zeichneSpielstein(int feldnummer, int spieler){
        
        zeichneSpielbrett();
        
        if(spielfeld[feldnummer] == 0){
            spielfeld[feldnummer] = spieler;
            if(spieler == 1) {
//Die untere Zeile  ist die Zeile 56:
                kreisparameter[feldnummer].farbeAendern("gruen");
            }else{
                dreieckparameter[feldnummer].farbeAendern("blau");
            }
        }
           
    }
}
 
Java:
for(int k=0; k<3; k++)
{
            for (int q=0; q<3; q++)
            {
                ....
            }
            f++; 
}

Wenn man da mal etwas löscht, sieht man auch, dass du f++ nur 3 mal, in der äußeren Schleife aufrufst. Also initialisierst du nur die ersten 3 Elemente.
 
Mhm ja ich weiß, das ist mir dann auch irgendwann mal aufgefallen 😉.

Hab den Fehler auch behoben, und alles funktioniert einwandfrei. Sieht jetzt so aus. (Nur zum Dokumentieren, vielleicht braucht es ja mal jemand)

Java:
public void zeichneSpielbrett(){
        Quadrat hintergrund = new Quadrat(190,0,0,"schwarz");

        int g = 50;
        int ax = 10;
        int f=0;
        String a = "rot";

        for(int k=0; k<3; k++){
            int bx = ax + 60*k;
            for (int q=0; q<3; q++){  
                feldparameter[f] = new Quadrat(g,ax,bx,a);
                kreisparameter[f] = new Kreis(g,ax,bx,a);
                dreieckparameter[f] = new Dreieck(g,g,ax+25,bx,a);
                if(ax==10){
                    ax=70;
                }else if(ax==70){
                    ax=130;
                }else if(ax==130){
                    ax=10;
                }
                f++;
            }
            if(f==3){
                f=3;
            }else if (f==6){
                f=6;
            }else {f++;} 
        } 
    }

Noch nä ganz kurze Frage. Ich weiß das eigentliche Thema ist eigentlich erledigt aber ..
Irgendwie lässt sich der Quelltext von meiner Klasse Spieler perfekt übersetzen, auch ausführen, und es kommt auch zu keine Fehlermeldung.

Und trozallem funktioniert diese Klasse nicht, "static public int spieler" wird nicht erhöht, und die Methode "zeichneSpielbrett()" nicht ausgeführt. 🙁

Warum?

Java:
import java.io.*;

public class Spieler{ 

    static public int feldnummer;
    static public int spieler = 0;
    static public String spielsymbol;

    public static void main (String[] args) throws IOException{
        { 
            BufferedReader eingabe = new BufferedReader(new InputStreamReader(System.in));;

            System.out.print("...?");
            spielsymbol = eingabe.readLine();


            if (spielsymbol=="Kreis"){
                 spieler++;
            }else if(spielsymbol=="Dreieck"){
                 spieler = spieler + 2;
            }
            
            System.out.print("...?");
            feldnummer = Integer.parseInt(eingabe.readLine());

            neuesspiel.zeichneSpielstein(feldnummer, spieler);
    }
}
 
Zuletzt bearbeitet:
Möchtest du über dieses Konstrukt nicht nochmal nachdenken?

Java:
            if(f==3){
                f=3;
            }else if (f==6){
                f=6;
            }else {f++;}

Wäre da nicht

Java:
            if (f != 3 && f != 6) {
                ++f;
            }

irgendwie sinnvoller?
 
Möchtest du über dieses Konstrukt nicht nochmal nachdenken?

Java:
            if(f==3){
                f=3;
            }else if (f==6){
                f=6;
            }else {f++;}

Wäre da nicht

Java:
            if (f != 3 && f != 6) {
                ++f;
            }

irgendwie sinnvoller?

Ja du hast recht.:toll: Danke =)

Ich bin noch ein totaler Anfänger, deswegen fällt mir sowas nicht immer auf =))
 

Zurück
Oben