Issue
I have a problem with getting to the Controller. I have a main template with two parts: Menu and Main Content In two separate FXML files I have the Menu (MenuTemplate.fxml) and Main Content (Content1Template.fxml). The loading of the Menu and Main Content proceeds correctly
The problem appears when Main Content wants to change the text after pressing the button. Content1Utils.java has to set text in Content1Controller.java. I guess I have to get to the controller. I just have a problem how to do it.
Luncher.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import sample.main.MainController;
import java.io.File;
import java.net.URL;
public class Launcher extends Application {
private static MainController mainController;
@Override
public void start(Stage primaryStage) throws Exception{
URL mainTemplate = new File("src/sample/main/MainTemplate.fxml").toURI().toURL();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(mainTemplate);
Parent root = loader.load();
mainController = loader.getController();
Scene scene = new Scene(root);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public MainController getMainController(){
return mainController;
}
}
MainController.java
package sample.main;
import com.jfoenix.controls.JFXDrawer;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.VBox;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class MainController {
@FXML private VBox rootBox;
@FXML private JFXDrawer menuBox;
@FXML private VBox contentBox;
@FXML
void initialize() throws IOException {
URL menuTemplate = new File("src/sample/menu/MenuTemplate.fxml").toURI().toURL();
VBox contentMenu = FXMLLoader.load(menuTemplate);
menuBox.setContent(contentMenu);
}
public void changeContentBox(VBox content){
contentBox.getChildren().setAll(content);
}
}
MenuController.java
package sample.menu;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import sample.Launcher;
import sample.main.MainController;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class MenuController {
@FXML private VBox menuRoot;
@FXML private Button menuButton1;
@FXML private Button menuButton2;
@FXML private Button menuButton3;
private MainController mainController;
@FXML
void initialize(){
}
public void clickButton1() throws IOException {
URL content1Template = new File("src/sample/content1/Content1Template.fxml").toURI().toURL();
VBox contentContent1 = FXMLLoader.load(content1Template);
mainController = new Launcher().getMainController();
mainController.changeContentBox(contentContent1);
}
}
Content1Controller.java
package sample.content1;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
public class Content1Controller {
@FXML private VBox content1root;
@FXML private Button content1Button;
@FXML private TextArea content1TextArea;
@FXML
void initialize(){
}
public void content1Button(){
Content1Utils contentUtils = new Content1Utils();
contentUtils.prepareText("XXX");
}
public void setTextInArea(String txt){
content1TextArea.setText(txt);
}
}
Content1Utils.java
package sample.content1;
public class Content1Utils {
public void prepareText(String txt){
String newTxt = txt + " - Test123";
new Content1Controller().setTextInArea(newTxt);
}
}
MainTemplate.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXDrawer?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="rootBox" prefHeight="442.0" prefWidth="665.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.main.MainController">
<children>
<HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" VBox.vgrow="ALWAYS">
<children>
<JFXDrawer fx:id="menuBox" style="-fx-background-color: #ebd534;" />
<VBox fx:id="contentBox" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-background-color: #34b7eb;" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</children>
</VBox>
MenuTemplate.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="menuRoot" prefHeight="442.0" prefWidth="100.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.menu.MenuController">
<children>
<Button fx:id="menuButton1" maxHeight="100.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#clickButton1" text="Button 1" VBox.vgrow="ALWAYS" />
<Button fx:id="menuButton2" maxHeight="100.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Button 2" VBox.vgrow="ALWAYS" />
<Button fx:id="menuButton3" maxHeight="100.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Button3" VBox.vgrow="ALWAYS" />
</children>
</VBox>
Content1Template.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="content1root" alignment="CENTER" prefHeight="442.0" prefWidth="565.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.content1.Content1Controller">
<children>
<Button fx:id="content1Button" contentDisplay="CENTER" mnemonicParsing="false" onAction="#content1Button" prefHeight="48.0" prefWidth="400.0" text="Button" textAlignment="CENTER">
<VBox.margin>
<Insets />
</VBox.margin>
</Button>
<TextArea fx:id="content1TextArea" maxWidth="400.0" prefHeight="200.0" prefWidth="400.0">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextArea>
</children>
</VBox>
ERROR
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
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:394)
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$353(GlassViewEventHandler.java:432)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
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$147(WinApplication.java:177)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771)
... 48 more
Caused by: java.lang.NullPointerException
at sample.content1.Content1Controller.setTextInArea(Content1Controller.java:25)
at sample.content1.Content1Utils.prepareText(Content1Utils.java:8)
at sample.content1.Content1Controller.content1Button(Content1Controller.java:21)
... 58 more
Solution
The problem is here:
public class Content1Utils {
public void prepareText(String txt){
String newTxt = txt + " - Test123";
new Content1Controller().setTextInArea(newTxt);
}
}
You are making a new controller instance that is not initialized from the FXML so it doesn't have a valid TextArea field. You don't want to have your utility class work this way.
Try:
public void content1Button(){
Content1Utils contentUtils = new Content1Utils(this);
contentUtils.prepareText("XXX");
}
Content1Utils.java:
package sample.content1;
public class Content1Utils {
private final Content1Controller controller;
public Content1utils(Content1Controller ctrl) {
this.controller = ctrl;
}
public void prepareText(String txt){
String newTxt = txt + " - Test123";
controller.setTextInArea(newTxt);
}
}
Answered By - swpalmer