Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I Change FXML Controller Variable Values in JavaFX before Showing Window?

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
like image 788
calben Avatar asked Dec 24 '12 05:12

calben


People also ask

How does FXML controller work in JavaFX?

How Does FXML Controller Work in JavaFX? We can set the controller class for the FXML document. The FXML controller class can bind the Graphical User Interface components declared within the FXML file together and also it makes the controller object becomes a mediator. We can set the controller for FXML in 2 ways:

How to get the current counter value from a FXML?

This way the controller of the included fxml will be injected to the field with the name <fx:id value>Controller. This is a fxml containing a StackPane with a Text node. The controller for this fxml file allows getting the current counter value as well as incrementing the counter: The controller of the included fxml is injected to this controller.

What is JavaFX MVC?

JavaFX controller works based on MVC (Model-View-Controller) JavaFX MVC can be achieved by FXML (EFF-ects eXtended Markup Language). FXML is an XML based language used to develop the graphical user interfaces for JavaFX applications as in the HTML.

What is the use of the Initialize () method in FXML?

The controller can use them later, such as binding them to model. The controller can have an accessible initialize () method, which should take no arguments and have a return type of void. The FXML loader will call the initialize () method after the loading of the FXML document is complete.


1 Answers

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.

like image 120
Yarrgh Avatar answered Nov 15 '22 07:11

Yarrgh