JavaFX Fehler zwischen View und Controller bei MouseEvent (MVC)

Hey, also ich möchte ein Vier Gewinnt im Model View Controller Pattern mit JavaFX machen, aber habe damit einige Probleme (bin auch ziemlicher Anfänger was JavaFX angeht).
Der Fehler tritt immer dann auf wenn das MouseEvent ausgelöst wird und der Controller den Input verarbeiten soll.
Bei StackOverflow und YouTube habe ich leider keine Hilfe gefunden, vielleicht kann mir hier jemand helfen 🙂

Die Spieler Klasse enthält nur die Drei Spieler (SPIELER, BOT und NONE) und den Color Code für den Chip.

[CODE lang="java" title="Fehler Output"]Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at de.medieninformatik.prog2.ConnectView$1.handle(ConnectView.java:51)
at de.medieninformatik.prog2.ConnectView$1.handle(ConnectView.java:47)
at com.sun.javafx.event.CompositeEventHandler$NormalEventFilterRecord.handleCapturingEvent(CompositeEventHandler.java:282)
at com.sun.javafx.event.CompositeEventHandler.dispatchCapturingEvent(CompositeEventHandler.java:98)
at com.sun.javafx.event.EventHandlerManager.dispatchCapturingEvent(EventHandlerManager.java:223)
at com.sun.javafx.event.EventHandlerManager.dispatchCapturingEvent(EventHandlerManager.java:180)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchCapturingEvent(CompositeEventDispatcher.java:43)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:52)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3470)
at javafx.scene.Scene$ClickGenerator.access$8100(Scene.java:3398)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3766)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)[/CODE]

[CODE lang="java" title="Main-Klasse"]public class Main{
public static void main(String[] args) {
ConnectView view = new ConnectView();
ConnectController control = new ConnectController(view);
}
}[/CODE]



[CODE lang="java" title="Controller Klasse"]import javafx.application.Application;
import javafx.scene.input.MouseEvent;

public class ConnectController {

private ConnectView view;
private ConnectModel model;

public ConnectController(ConnectView view) {
this.view = view;
Application.launch(view.getClass());
}

public void handleChipPress(int x, int y){
System.out.println(x + " " + y);
}
}[/CODE]

View Klasse (mit JavaFX)

[CODE lang="java" title="View Klasse (mit JavaFX und MouseEvent)"]public class ConnectView extends Application {
private int FELD_SIZE;
private int FELD_HEIGHT;
private int FELD_WIDTH;
private Group feldGroup = new Group();
public ConnectController controller;

public ConnectView(){
this.FELD_SIZE = 100;
this.FELD_HEIGHT = 6;
this.FELD_WIDTH = 6;
}

public ConnectView(ConnectController controller){
this.FELD_SIZE = 100;
this.FELD_HEIGHT = 6;
this.FELD_WIDTH = 6;
this.controller = controller;
}

public void setController(ConnectController controller){
this.controller = controller;
}

private Parent build(){
Pane root = new Pane();
root.setPrefSize(FELD_WIDTH * FELD_SIZE, FELD_HEIGHT * FELD_SIZE);
root.getChildren().addAll(feldGroup);

for (int y = 0; y < FELD_HEIGHT; y++){
for (int x = 0; x < FELD_WIDTH; x++){
Chip chip = new Chip(x, y);
//feldGroup.getChildren().add(new Chip(x, y));
chip.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
chip.setS(Spieler.SPIELER);
controller.handleChipPress(chip.getX(), chip.getY());
}
});
feldGroup.getChildren().add(chip);
}
}
return root;
}

@Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(build());
stage.setTitle("Vier Gewinnt");
stage.setScene(scene);
stage.show();
}
}[/CODE]

[CODE lang="java" title="Chip Klasse"]public class Chip extends Circle {
private Spieler s = Spieler.NONE;
private int x;
private int y;

Chip(int x, int y){
this.x = x;
this.y = y;
setFill(s.getC());
setRadius((int)(Spielbrett.FELD_SIZE / 2));
setCenterX(x * Spielbrett.FELD_SIZE + (int)Spielbrett.FELD_SIZE/2);
setCenterY(y * Spielbrett.FELD_SIZE + (int)Spielbrett.FELD_SIZE/2);
}

public Spieler getS() {
return s;
}

public void setS(Spieler s) {
this.setFill(s.getC());
this.s = s;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}
}[/CODE]
 
Was steht denn in deiner Spieler Klasse drin
wahrscheinlich:
wurde dein Spieler nicht Erzeugt,
die Farbe des Spielers wurde nicht gesetzt

und dass es ein EventFilter ist macht gar keinen sinn

aber allgemein ist dein Code sehr verwirrend

...bei Variablen die man komplett groß schreibt haben die eigenschaft von static final soweit ich es weis
das trifft aber bei dir nicht zu
 
Zuletzt bearbeitet von einem Moderator:
Was steht denn in deiner Spieler Klasse drin
wahrscheinlich:
wurde dein Spieler nicht Erzeugt,
die Farbe des Spielers wurde nicht gesetzt

und dass es ein EventFilter ist macht gar keinen sinn

aber allgemein ist dein Code sehr verwirrend

...bei Variablen die man komplett groß schreibt haben die eigenschaft von static final soweit ich es weis
das trifft aber bei dir nicht zu
Ja ich weiß, ist ziemlicher Spaghetticode 😅 weiß es leider nicht besser, sorry!

[CODE lang="java" title="Spieler Klasse"]import javafx.scene.paint.Color;

public enum Spieler {
SPIELER(Color.RED), BOT(Color.BLUE), NONE(Color.GREY);

public final Color c;

Spieler(Color c){
this.c = c;
}

public Color getC() {
return c;
}
}[/CODE]
 
Kannst du mal ausprobieren und die Zeile finden ab wann der Null pointer kommt... mit System out println
 
Aber die Enum gefällt mir so schon recht gut - nur lass bitte Abkürzungen weg: getColor statt getC bitte.

Und Code verbessern geht über mehrere Wege:
a) Übungen: Eine Übung ist z.B. gnadenlos Methoden zu limitieren a.la. maximal 5 Codezeile und maximal 1 oder 2 Einrückungen.
b) Regeln umsetzen - clean-code-developer.de wäre da eine Empfehlung
c) Mehr Theorie also Dinge vertiefen in Gebieten wie: Pattern, Clean Code, ...

Generell geht vieles nur über Praxis.

Kannst du mal ausprobieren und die Zeile finden ab wann der Null pointer kommt... mit System out println
Die Zeilen mit der NPE haben wir ja schon:
at de.medieninformatik.prog2.ConnectView$1.handle(ConnectView.java:51)
at de.medieninformatik.prog2.ConnectView$1.handle(ConnectView.java:47)
Da brauchen wir nur die Zeile 51 und auch 47.

Das kann eigentlich ja nur hier sein:
Java:
                chip.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        chip.setS(Spieler.SPIELER);
                        controller.handleChipPress(chip.getX(), chip.getY());
                    }
                });

Nur welche Zeile genau? Ich habe bei dem Code so hier im Browser keinen überblick. Ich würde vermuten, dass controller null ist. Aber das ist nur geraten.
 
Aber die Enum gefällt mir so schon recht gut - nur lass bitte Abkürzungen weg: getColor statt getC bitte.

Und Code verbessern geht über mehrere Wege:
a) Übungen: Eine Übung ist z.B. gnadenlos Methoden zu limitieren a.la. maximal 5 Codezeile und maximal 1 oder 2 Einrückungen.
b) Regeln umsetzen - clean-code-developer.de wäre da eine Empfehlung
c) Mehr Theorie also Dinge vertiefen in Gebieten wie: Pattern, Clean Code, ...

Generell geht vieles nur über Praxis.


Die Zeilen mit der NPE haben wir ja schon:

Da brauchen wir nur die Zeile 51 und auch 47.

Das kann eigentlich ja nur hier sein:
Java:
                chip.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        chip.setS(Spieler.SPIELER);
                        controller.handleChipPress(chip.getX(), chip.getY());
                    }
                });

Nur welche Zeile genau? Ich habe bei dem Code so hier im Browser keinen überblick. Ich würde vermuten, dass controller null ist. Aber das ist nur geraten.
wie vom TE schon geschrieben tritt der Fehler nur beim Mouse Event auf
also kann es nur Am Spieler
oder Controller liegen
und das hätte man ausprobieren können...wenn alles noch gut geht bis zum controller muss es dann am controller liegen..
Wollte halt dass der TE selber schaut bis wie weit es geht und ab wann es abschmiert
dann reduziert sich das Feld wo ein Fehler sein könnte auf 1 Zeile


Ab einem Gewissen grad an Efahrung sollte man es schaffen können mit Sysout oder Break Points oder irgendwie einer anderen Methode einen Fehler zu finden .. wenn man ihn gefunden hat löst ihn google in Sekunden oder ist so offensichtlich dass man es sieht ...nur das finden ist schwer( meistens 😀 )
 
Was ich ja nur meinte: Der Stacktrace nennt den genauen Ort. Daher muss man keine zusätzliche Ausgabe einfügen, um den genauen Ort zu finden. Das Problem hier im Forum ist nur, dass die ersten Zeilen der Datei nicht mit kopiert wurden, daher haben wie nicht die genauen Zeilennummern.
 
und nur so nebenbei erwähnt in der Doppel Schleife wird für jeden Pixel 1 Chip erstellt mit einem Radius von
Java:
setRadius((int)(Spielbrett.FELD_SIZE / 2));
das passt noch nicht ganz
 
Aber die Enum gefällt mir so schon recht gut - nur lass bitte Abkürzungen weg: getColor statt getC bitte.

Und Code verbessern geht über mehrere Wege:
a) Übungen: Eine Übung ist z.B. gnadenlos Methoden zu limitieren a.la. maximal 5 Codezeile und maximal 1 oder 2 Einrückungen.
b) Regeln umsetzen - clean-code-developer.de wäre da eine Empfehlung
c) Mehr Theorie also Dinge vertiefen in Gebieten wie: Pattern, Clean Code, ...

Generell geht vieles nur über Praxis.


Die Zeilen mit der NPE haben wir ja schon:

Da brauchen wir nur die Zeile 51 und auch 47.

Das kann eigentlich ja nur hier sein:
Java:
                chip.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        chip.setS(Spieler.SPIELER);
                        controller.handleChipPress(chip.getX(), chip.getY());
                    }
                });

Nur welche Zeile genau? Ich habe bei dem Code so hier im Browser keinen überblick. Ich würde vermuten, dass controller null ist. Aber das ist nur geraten.
Es ist diese Zeile:

[CODE lang="java" title="Es ist diese Zeile" highlight="5"] chip.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
chip.setS(Spieler.SPIELER);
controller.handleChipPress(chip.getX(), chip.getY());
}
});[/CODE]

Ich habe außerdem mal getestet die handleChipPress Methode in der Controller Klasse static zumachen, um sie dann über die Klasse einfach aufzurufen und da hat die Funktion einwandfrei funktioniert.
Denke es muss dann wohl daran, dass der Controller an der Stelle des Events Null ist.
 
Java:
ConnectView view = new ConnectView();
hier erstellst du eine View mit dem Standard Konstruktor in deiner Main der keinen Controller setzt
aber im Eventhandler stellst du die Verbindung zu dem nie gesetzten Controller her

Java:
    public ConnectView(ConnectController controller){
        this.FELD_SIZE = 100;
        this.FELD_HEIGHT = 6;
        this.FELD_WIDTH = 6;
        this.controller = controller;
    }

    public void setController(ConnectController controller){
        this.controller = controller;
    }
diese Zwei Sachen werden doch nie benutzt




zu den Punktenmit dem Radius ...es ist bemerkenswert das das tatsächlich funktioniert..hat ziemlich falsch ausgesehen 😀


Java:
    public static void main(String[] args) {
        ConnectView view = new ConnectView();
        ConnectController control = new ConnectController(view);
    }
der eiznige controller den du jemals hast verlierst du hier
du musst ihn noch setzen...
 
Java:
ConnectView view = new ConnectView();
hier erstellst du eine View mit dem Standard Konstruktor in deiner Main der keinen Controller setzt
aber im Eventhandler stellst du die Verbindung zu dem nie gesetzten Controller her

Java:
    public ConnectView(ConnectController controller){
        this.FELD_SIZE = 100;
        this.FELD_HEIGHT = 6;
        this.FELD_WIDTH = 6;
        this.controller = controller;
    }

    public void setController(ConnectController controller){
        this.controller = controller;
    }
diese Zwei Sachen werden doch nie benutzt




zu den Punktenmit dem Radius ...es ist bemerkenswert das das tatsächlich funktioniert..hat ziemlich falsch ausgesehen 😀


Java:
    public static void main(String[] args) {
        ConnectView view = new ConnectView();
        ConnectController control = new ConnectController(view);
    }
der eiznige controller den du jemals hast verlierst du hier
du musst ihn noch setzen...

[CODE lang="java" title="Diese Methode habe ich noch zur Controller Klasse hinzugefügt"]public void initView(ConnectView view){
if(view == null){
throw new IllegalStateException();
}
this.view = view;
Application.launch(view.getClass());
}[/CODE]

[CODE lang="java" title="So habe ich das ganze dann in der Main eingesetzt"] public static void main(String[] args) {
ConnectView view = new ConnectView();
ConnectController control = new ConnectController();
control.initView(view);
view.setController(control);
}[/CODE]

Jedoch noch der gleiche Fehler 😀
 
du führst build() aus setzt bei jedem event einen null pointer und danach setzt du den Controller

das ist wie wenn du sagst "ich geb dir meine Süßigkeiten jetzt"
und dann erst einkaufen gehst weil du keine hattest


wäre der "start" nicht auf 3 klassen aufgeteilt wäre es auch einfacher zu entziffern
 
Java:
package application;
import controller.SwitchController;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {
        public static void main(String[] args) {
            launch(args);
        }
        public void start(Stage sta) throws Exception {
            SwitchController switcher = new SwitchController();
            switcher.initialize();
            sta.setScene(new Scene(switcher.setTheMainScene()));
            sta.show();
        }
}
so sieht eine meiner Main Methoden aus...ist zwar auch nicht das geilste auf der Welt aber lesbarer
 

Neue Themen


Zurück
Oben