5

I want to change the labels and text in a popup FXML window before it is shown. This is being done because all of the Help items will be very similar and I wanted to make a template FXML and then change the values of the labels and text area accordingly to reduce coding.

I'm surprised I haven't come across a template method in JavaFX though. If there's a better way to go about this, please do suggest it.

For the task at hand, I have the following:

@FXML private void documentationAction(ActionEvent action) throws IOException { Stage dialogue = new Stage(); Parent root = null; FXMLLoader loader = new FXMLLoader(); root = loader.load(getClass().getResource("dialogues/dialogue.fxml")); Scene scene = new Scene(root); /* * change text values in title (Label) and text (TextArea) * and change the behavior of the findMore button */ dialogue.setTitle("Documentation"); dialogue.setScene(scene); dialogue.show(); } 

I would like to be able to change variables inside the FXML file, for which I've made getters and setters in the controller class, but I can't figure how to do this.

Is there a way? It seems like it would be necessary for changing information between windows in multi-windowed applications, so I'm sure there's something simple that I'm missing.

UPDATE Code for controller:

public class DialogueController implements Initializable { @FXML private Button more; @FXML private Button close; @FXML private TextArea text; @FXML private Label title; public TextArea getText() { return text; } public void setText(String text) { this.text.setText(text); } public Label getTitle() { return title; } public void setTitle(String text) { this.title.setText(text); } @FXML public void closeAction(ActionEvent action) { // get a handle to the stage Stage stage = (Stage) close.getScene().getWindow(); // do what you have to do stage.close(); } @FXML public void moreAction(ActionEvent action) { } @FXML public void makeDocumentation(ActionEvent action) { this.title.setText("Documentation"); } /** * Initializes the controller class. */ @Override public void initialize(URL url, ResourceBundle rb) { } } 

Full Dialogue FXML

<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.net.*?> <?import java.util.*?> <?import javafx.geometry.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" padding="$x1" prefHeight="500.0" prefWidth="400.0" styleClass="mainFxmlClass" xmlns:fx="http://javafx.com/fxml" fx:controller="pdbpro.dialogues.DialogueController"> <children> <GridPane alignment="CENTER" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <children> <Label fx:id="title" alignment="CENTER_LEFT" prefWidth="-1.0" styleClass="title" text="Title" underline="false" visible="true" GridPane.columnIndex="0" GridPane.rowIndex="0"> <GridPane.margin> <Insets fx:id="x1" /> </GridPane.margin> </Label> <TextArea fx:id="text" editable="false" focusTraversable="false" prefWidth="200.0" wrapText="true" GridPane.columnIndex="0" GridPane.rowIndex="1"> <GridPane.margin> <Insets bottom="24.0" left="15.0" right="15.0" /> </GridPane.margin> </TextArea> <ToolBar GridPane.columnIndex="0" GridPane.rowIndex="2"> <items> <Button fx:id="more" mnemonicParsing="false" text="Find more" /> <Button fx:id="close" mnemonicParsing="false" onAction="#closeAction" text="Close" /> </items> <GridPane.margin> <Insets bottom="14.0" /> </GridPane.margin> </ToolBar> </children> <columnConstraints> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> </columnConstraints> <padding> <Insets fx:id="x1" /> </padding> <rowConstraints> <RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" valignment="CENTER" vgrow="NEVER" /> <RowConstraints maxHeight="1.7976931348623157E308" minHeight="50.0" prefHeight="0.0" vgrow="ALWAYS" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> </rowConstraints> </GridPane> </children> <stylesheets> <URL value="@dialogue.css" /> </stylesheets> </AnchorPane> 

Full stack trace of error at these lines

FXMLLoader loader = new FXMLLoader(); Parent root = loader.load(getClass().getResource("dialogues/dialogue.fxml")); DialogueController dc = loader.getController(); dc.makeDocumentation(); //ERROR Scene scene = new Scene(root); java.lang.RuntimeException: java.lang.reflect.InvocationTargetException at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1440) at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92) at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53) at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:28) at javafx.event.Event.fireEvent(Event.java:171) at javafx.scene.control.MenuItem.fire(MenuItem.java:456) at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1188) at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$6.handle(ContextMenuContent.java:1139) at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$6.handle(ContextMenuContent.java:1137) at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170) at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92) at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53) at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33) at javafx.event.Event.fireEvent(Event.java:171) at javafx.scene.Scene$MouseHandler.process(Scene.java:3324) at javafx.scene.Scene$MouseHandler.process(Scene.java:3164) at javafx.scene.Scene$MouseHandler.access$1900(Scene.java:3119) at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1559) at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2261) at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:228) at com.sun.glass.ui.View.handleMouseEvent(View.java:528) at com.sun.glass.ui.View.notifyMouse(View.java:922) at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29) at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73) at java.lang.Thread.run(Thread.java:722) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1435) ... 37 more Caused by: java.lang.NullPointerException at pdbpro.MainController.documentationAction(MainController.java:82) ... 42 more 

3 Answers 3

5

One way I can see is to make your controller implement initializable and implement the initialize method. The initialize method will be called automatically when the controller is created by the fxml loader. When the inititialize method is called all the fxml object declared should be initialized and ready to be customized.

[edit] After reading the docs for initializable, it says that if a method called initialize with no args is created that it will be called automatically with the fxml loader. So from what I understand, you don't need to implement initializable. Just create an initialize method with no args.

If needed, further info may be found in an introduction to fxml.

Sign up to request clarification or add additional context in comments.

4 Comments

The controller is already initialized, but the initialize method was, in this case, blank: @Override public void initialize(URL url, ResourceBundle rb) { } If I wanted to then edit the fields of the class, I tried Uluk's suggestion, but I got a null pointer. Could you expand on what you meant? Thanks!
In that method you'd do your customization that you want. You can call your getters and setters and do everything to change the labels and anything you need to from within the controller since the initialize method is already inside it
What would I pass to the initializer to indicate what values I want set during the initialization? Or how would I add another parameter to the method, say a string, to indicate to what I want the values initialized?
You can't pass it another parameter. What I would do is create a model for the controller and pass that the parameters you want and then in the inititialize method in the controller, it would talk to the model to get the values it needs
3

Try this:

root = (Parent) loader.load(getClass().getResource("dialogues/dialogue.fxml").openStream()); DialogueController dc = loader.getController(); dc.setTitle("title"); dc.setTextArea("text"); // and so on.. ... dialogue.show(); 

Assert that the DialogueController dc is not null. And assuming the "title" is a Label in fxml file with fx:id=titleLabel, it should be backed in your controller class like follows:

... @FXML private Label titleLabel; ... public void setTitle(String txt) { titleLabel.setText(txt); } ... 

12 Comments

I got a null pointer exception with this on the setTitle line. Caused by: java.lang.NullPointerException at pdbpro.MainController.documentationAction(MainController.java:84)
@Kylamus. Have you defined fx:controller attribute in your dialogue.fxml? And did that controller's initialize method run while loading dialogue.fxml?
It appears to all be initialized properly and the controller has been fully defined.
@Kylamus. Then your DialogueController should not be null at line dc.setTitle("title");. The NPE comes from setTitle() I guess. Can I see the code of controller class at least getters/setters? See update.
reduced code:: public class DialogueController implements Initializable { @FXML private Button more; @FXML private Button close; @FXML private TextArea text; @FXML private Label title; public TextArea getText() { return text; } public void setText(String text) { this.text.setText(text); } public void setTitle(String text) { this.title.setText(text); } @Override public void initialize(URL url, ResourceBundle rb) { } }
|
1

I would suggest you to hide all FXML loading code to controller. For that it is possible to extend a Stage class:

Controller:

public class DialogueController extends Stage implements Initializable{ @FXML private Button more; @FXML private Button close; @FXML private TextArea text; @FXML private Label title; public DialogueController(Parent parent){ FXMLLoader loader = new FXMLLoader(getClass().getResource("dialogues/dialogue.fxml")); fxmlLoader.setController(this); super.setTitle("Documentation"); try{ setScene(new Scene((Parent) loader.load())); }catch(IOException e){ e.printStackTrace(); } /* * Change values here */ } } 

Call your controller:

@FXML private void documantationAction(ActionEvent action) throws IOException{ DialogueController controller = new DialogueController(null); controller.show(); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.