Issue
I'm working on a Game project with JavaFX and a MVC Architecture
Here are one of my views
package fr.arnoux23u.javano.mvc.views;
import fr.arnoux23u.javano.mvc.*;
import javafx.fxml.*;
import javafx.scene.control.TextArea;
import java.net.URL;
import java.util.ResourceBundle;
/**
* @author arnoux23u
*/
public class ServerView implements Initializable, Observer {
@FXML
private TextArea clientsList;
@Override
public synchronized void update(Model m) {
System.out.println("[UPDATE] "+Thread.currentThread().getName());
clientsList.setText("test");
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
System.out.println("[INITIALIZE] "+Thread.currentThread().getName());
clientsList.setText("Aucun joueur ici");
}
}
And my FXML File
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.arnoux23u.javano.mvc.views.ServerView">
<Label text="JavaNo - Server">
<font>
<Font size="23.0" />
</font>
</Label>
<Label alignment="CENTER" text="Connected Clients">
<font>
<Font size="23.0" />
</font>
</Label>
<TextArea fx:id="clientsList" editable="false" maxWidth="200.0" prefHeight="200.0" prefWidth="200.0" style="-fx-focus-color: -fx-control-inner-background;" text=" ">
<VBox.margin>
<Insets top="20.0" />
</VBox.margin>
<font>
<Font size="18.0" />
</font></TextArea>
</VBox>
When I load the app, the text of the TextArea clientsList is correctly set to "Aucun joueur ici" but when I want to update the text (with MVC), I've a NullPointerException
on clientsList
First, I thought it was a Thread Error because the Thread who runs the update
method was not the "JavaFX Application Thread"
So in my MVC Controller, I use the Platform.runlater() method.
@Override
public void notifyObservers() {
observers.forEach(o -> {
System.out.println("[FOREACH] "+Thread.currentThread().getName());
Platform.runLater(() -> {
System.out.println("[PLATFORM] "+Thread.currentThread().getName());
o.update(this);
});
});
}
The output when I call the update is
[INITIALIZE] JavaFX Application Thread
[FOREACH] Thread-3
[PLATFORM] JavaFX Application Thread
[UPDATE] JavaFX Application Thread
But even with the runLater method, I've a NullPointerException
Here is the complete stack trace
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException: Cannot invoke "javafx.scene.control.TextArea.setText(String)" because "this.clientsList" is null
at fr.arnoux23u.javano/fr.arnoux23u.javano.mvc.views.ServerView.update(ServerView.java:34)
at fr.arnoux23u.javano/fr.arnoux23u.javano.mvc.Game.lambda$notifyObservers$1(Game.java:54)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
I hope someone can help me.
Thank's
Solution
See step 3 of this description of FXMLoader operation:
If there is a fx:controller attribute on the root element, the FXMLLoader creates an instance of the specified class.
So, if you create a new instance explicitly in your code, and the loader also creates a new instance, then only the loader instance will have fxml values injected.
I guess, with a high degree of certainty, that is what is happening with your code.
Answered By - jewelsea
Answer Checked By - Katrina (JavaFixing Volunteer)