[Java] Methode aus einem Thread anders, als vom main aus?

V1tzl1

Lt. Junior Grade
Registriert
Sep. 2004
Beiträge
384
Hallo.
Ich schreibe gerade mit Java vor mich hin, um es ein bisschen zu lernen. Dabei bin ich mal wieder auf ein Problem gestoßen, das ich diesmal allerdings nicht so einfach erklären kann.

Zu meinem Programm
Ich habe ein "Hauptfaden" und einen Thread, der nebenher läuft. Beide Threads haben eine Referenz auf ein von mir erstelltes Objekt. Will ich nun eine bestimmte Methode dieses Objekts aufrufen, tut er dies auch, jeoch wird in dieser Methode dann eine weitere methode aufgerufen, welche dann einen Fehler verursacht.
Diese aufgerufene Methode sieht so aus
Code:
void fall()
  {
    System.out.println("fällt...");
    this.draw(Color.white);               // Hier gibt er den Fehler raus
    y = (int) (y+5);
    this.draw(Color.blue);
  }
Das fällt wird ganz normal in der Konsole ausgegeben, beim draw wird allerdings ein Fehler ausgegeben, aber nur wenn ich fall vom nebenthread her aufrufe.
Der Fehler ist ein NullPointerException. Laut Doku wird diese Exception geworfen, wenn man auf ein Objekt zugreifen will, das gar kein Objekt ist. Ich sehe in der Methode aber nur ein Objekt verwendet und das ist das Color Objekt, das sich ja nicht ändert, egal von wo ich es aufrufe.

Ich hoffe ihr konntet mein Problem verstehen. Wenn ihr noch mehr Code, oder Angaben braucht, sagt es einfach. Schonmal danke für eure Hilfe
 
Also eine Referenz auf das Objekt kannst du im anderen Thread schon mal nicht haben. In JAVA wird alles byValue übergeben. Vielleicht liegt da der Grund für den Fehler. Poste doch mal den ganzen Code.
 
Also ich habe 2 Referenzen auf das gleiche Objekt. Daran kann der Fehler aber nicht liegen, da er ja in beiden Fällen die Methode fall startrt (s. Konsolenmeldung).
Braucht ihr wirklich den ganzen Code dafür, nicht dass ich damit ein Problem hätte, aber er ist verdammt lang...
 
Also bei Threads muss man vorsichtig sein das sie sich nicht überschreiben.
Dein Problem könnte an dem this Objekt liegen, sonder doch einwenig Code aus in verschiedene Klassen um mit deren Instanzen zu hantieren anstatt mit this zu arbeiten.

Wenn du mehr von deinem Code veröffentlichst könnte man mehr sagen.
 
Ok wie schon oben gesagt, habe ich kein Problem den Code zu veröfentlichen, ich wollte euch eigentlich nur arbeit sparen...
Egal ich hab die Dateien mal angehängt.
Hier ne kleine Beschreibung der Klassen und deren Methoden

public class main
Hier ist der Programm startpunkt. Er ruft atm nur ein JFrame auf.

public class Fenster extends JFrame
Beim erstellen von Fenster wird eine Instanz vom Objekt Plane (Erklärung folgt gleich) erstellt, sowie einne Instanz von Gravity (ein Thread!). Dieser Thread wird danach gestartet.
In der Methode paint, wird zuerst das Grafikobject an Plane übergeben, da auch dieses Zeichnen muss. Danach wir es gezeichnet. Dann wird nachgesehen, ob etwas getan werden soll.
Dann folgt noch die Überwachung auf Tastatureingaben. Die gedrückte Taste wird lediglich gespeichet und per repaint dann im paint Block verarbeitet.

public class Plane
Die Instanz von Plane ist ein kleines Flugzeug. Dieses kann mit der Methode draw gezeichnet werden. Dabei greift draw auf die Variablen x un y (Position) sowie den winkel der Spitze zur x-Achse. In der Methode setGraphics bekommt er bei jedem repaint das gültige Graphics Objekt.
In der Methode turn kann der Flieger gedreht werden. Er erwartet einen Integer um wie viel Grad er gedreht werden soll.
Die Methode fall lässt den Flieger um 5 Pixel fallen.
Die beiden draw's sind hier auskommentiert, damit ihr das Programm erst einmal 'in Action' erleben könnt. Nehme ich die beiden in den Code auf, ergibt sich der Fehler

public class Gravity extends Thread
Der Thread Gravity tut nichts anderes, als jede Sektunde die Methode Plane.fall() auszu führen.

Das Ganze Projekt läuft soweit, bis man die beiden draws in das Programm mit hinein nimmt.
Ich hoffe ihr könnt mir helfen und steigt durch den Code durch ;)
Schonmal vielen Dank V1tzl1
 

Anhänge

Dein Grafic Element gr hat den Wert null, sollange das Fenster noch nicht erstellt wurde.
deswegen musst du das abfangen, erst wenn dieser Wert != null ist kannst du damit arbeiten.

Code:
    // Konstruktoren
  Fenster(int x, int y)
  {
    setSize(x,y);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setTitle("Space Flyer");
    enableEvents(AWTEvent.KEY_EVENT_MASK);      // Listener aktivieren
    //pl1 = new Plane(gr,140,140,90);
    //grav = new Gravity(pl1, this);
    //grav.start();
    setBackground(Color.white);

  }

Code:
public class main
{
	static Plane pl1;
	static Gravity grav;
	static Graphics gr;
  public static void main ( String[] args )
  {
    Fenster frame = new Fenster(640,480);
    frame.setVisible( true );
    frame.gr=frame.getGraphics();

    System.out.println(frame.gr);
    pl1 = new Plane(frame.gr,140,140,90);
    grav = new Gravity(pl1, frame);
    grav.start();
    
    frame.pl1=pl1;
    frame.grav=grav;
    
  }
}
 
und was ich jetzt noch gesehen habe, deine Klasse solltest du nicht main nennen da dies ein reserviertes Wort ist. das kann auch zu Problemen führen.
 
Jo jetzt klappt alles wunderbar, vielen Dank.
Eine weitere Frage hätte ich alledrings noch. Wenn ich das Fenser neu zeichnen lasse, also zb vergrößere, dann setzt er die Hintergrundfarbe auf so ein komisches hell grau. Wie klann ich das verhindern?
 
leider weis ich das auch nicht.
Die Möglichkeit die ich dabei sehe, sieht so aus:
Da müsstest du aber ne menge umbauen, ein JPanel als Hintergrund das genauso groß ist wie dein Fenster. dann musst du aber dein Flugzeug auf dem JPanel platzieren und nicht mehr direkt auf deinem Frame Fenster.

Code:
private Container cp;
private JPanel panel;

Fenster(int x, int y){
    setSize(x,y);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setTitle("Space Flyer");
    enableEvents(AWTEvent.KEY_EVENT_MASK);      // Listener aktivieren
    //pl1 = new Plane(gr,140,140,90);
    //grav = new Gravity(pl1, this);
    //grav.start();
    setBackground(Color.white);
    
    cp=getContentPane();
    panel=new JPanel();
    panel.setPreferredSize(new Dimension(x,y));
    panel.setBackground(Color.white);
    cp.add(panel);
  }
 
V1tzl1 schrieb:
Wenn ich das Fenser neu zeichnen lasse, also zb vergrößere, dann setzt er die Hintergrundfarbe auf so ein komisches hell grau. Wie klann ich das verhindern?

Indem du die Komponente transparent zeichnen lässt. Das erreichst du durch
Code:
komponente.setOpaque(true)
.

Gruß,
stengbiegel
 
Hi vielen Dank für eure Antworten. stengbiegel's Antwort gefällt mir natürlich ein wenig besser, da es nur eine kleine Änderung ist. Jedoch verstehe ich nicht, welche Komponente du meinst und wo ich das einbauen muss.

MfG V1tzl1
 
Die Komponente die er meint ist zum Beispiel ein JPanel, das diese Methode unterstützt.
Du benutzt jedoch diese JPanels noch nicht.
Dein JFrame unterstütz setOpaque(true) nicht. Soweit ich das nachvollziehen konnte wird die Transparente Darstellung bei einem JFrame generell nicht angewendet.
Also wirst du um eine Zweite Arbeitsfläche (JPanel) nicht herum kommen.
 
Hi sorry für die späte Antwort, aber wie zu erwarten war hab ich das mit den Panels nicht wirklich hinbekommen und hab desshalb erstmal ausprobiert...

Könnt ihr euch vlt noch mal ansehen, was ich mir da jetzt zurechtgebogen habe?
Ich habe das Panel jetzt gleich mit der Klasse Plane verbunden, da ich ja eh nur den Flieger zeichne.
(Edit: Das klappt auch, nur irgentwas malt jetzt ständig weiß über das ganze Fenster zwischendurch sieht man den Flieger aber)

Schonmal vielen Dnak für die Hilfe bis jetzt
V1tzl1
 

Anhänge

Zuletzt bearbeitet:
Hi,
wenn du paint() in Plane nicht überschreibst zeichnet Java immer über das von dir gezeichnete drüber.
Gruß,
stengbiegel
 

Anhänge

Hi stengbiegel, erstmal vielen Dank für deine Hilfe. Das Problem, das du nennst, sit in der Tat eins, das mir einleuchtet. Nur leider hilft das nicht, das gesammt Problem zu beheben. Die von dir gepostete Klasse liefert mir immer noch ein weißes Fenster :(.
Ist da vlt noch was, was ich übersehen habe?

MfG V1tzl1
 
Hi,
bei mir war der Flieger zu sehen und liess sich drehen, sonst hätte ich es nicht gepostet ;)
Jedenfalls zeigt dir der Code das Prinzip, daran kannst du dich ja dann langhangeln. Also ungefähr so:

Code:
public void paint(Graphics g){
  super.paint(g); // lass mal Swing das Panel zeichnen
  g.drawLine(...); // ab hier dann den Flieger zeichnen
  ...
}

Gruß,
stengbiegel
 
Okay, hätte ja sein könen, dass du in ner anderen Klasse noch was geändert, aber nicht geschrieben hast. Naja egal, wie schon erwähnt, weiß ich ja jetzt, woran es gelegen hat und werd mich mal drum kümmern.
Nochmal vielen Dank
 
Nicht schön aber selten
ne neue Klasse

public class CContent extends JPanel

neu in:
public class Fenster extends JFrame

neu Instanz:
private CContent m_content;

inhalt anpassen in :
public void paint(Graphics g)

das geht
 

Anhänge

Zuletzt bearbeitet:
Zurück
Oben