GoXR3Plus GoXR3Plus - 1 month ago 27
Java Question

JavaFX - Many Static FXML Controllers

A

JavaFX
application exists and the application is starting from the
Main.class
file which
extends Application
:

public class Main extends Application {

/**
* Keep a reference to the main Stage
*/
public static Stage stage;
/**
* MainScene Controller
*/
public static MainScene mainSceneController;
/**
* The Capture Window of the application
*/
public static CaptureWindow captureWindowController;
/**
* Settings Scene Controller
*/
public static SettingsController settingsController;

@Override
public void start(Stage primary) throws Exception {

stage = primary;
..........

// CaptureWindow
FXMLLoader loader1 = new FXMLLoader(getClass().getResource("/fxml/CaptureWindow.fxml"));
loader1.load();
captureWindowController = loader1.getController();

// MainScene
mainSceneController = new MainScene();

.........
}

}





Description

As you can see above I have 3
FXMLControllers
(one is reusable[
extends StackPane
],others not).I have declared all of them static cause i want to access variables from one
FXMLController
from the other
FXMLControllers
.I use this strategy every time I use
JavaFX
and I don't think is good...

How I can change the code below so I can access variables or methods of one
FXMLController
from other
FXMLController
? Is that possible without using
static
keyword?

Consider that the Controllers are represented from different classes which can be in different packages.




Also before writing this question I had a look Static @FXML variables in FXML Controller

Answer

JavaFx is mostly composed of set of [well designed] tools but unfortunately by itself does not provide a good framework for creating complex UI designs e.g. MVC/MVP patterns, view flows and actions on multiple controllers, So you have to rely on third-party application frameworks for those for example:

In my opinion none of them are widely used or mature enough to be considered a de facto standard but using them is encouraged.


Example Using DataFx

DataFx uses a concept named Flow to associate views sharing a flow of events (and possibly data) among themselves. By using Flow combined with EventSystem you can define and access methods on other controllers and assign custom event listeners to various events associated with JavaFx Nodes in different controllers sharing a flow.

Here is an example from DataFx samples which represents two separate sender and receiver views with distinct FXML files and controllers:

enter image description here

public class EventSystemDemo extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

    HBox box = new HBox();
    box.setSpacing(12);
    box.setPadding(new Insets(12));
    box.setFillHeight(true);
    box.setAlignment(Pos.CENTER);

    Flow senderFlow = new Flow(ProducerController.class);
    box.getChildren().add(senderFlow.start());

    Flow receiverFlow = new Flow(ReceiverController.class);
    box.getChildren().add(receiverFlow.start());

    primaryStage.setScene(new Scene(box));
    primaryStage.show();

    }

    public static void main(String... args) {
        launch(args);
    }
}

Sender view controller:

@ViewController("producer.fxml")
public class ProducerController {

    @FXML
    @EventTrigger()
    private Button sendButton;

    @FXML
    private TextField textField;

    @EventProducer("test-message")
    private String getMessage() {
        return textField.getText();
    }

}

Receiver view controller:

@ViewController("receiver.fxml")
public class ReceiverController {

    @FXML
    private Label messageLabel;

    @OnEvent("test-message")
    private void onNewChatMessage(Event<String> e) {
        messageLabel.setText(e.getContent());
    }
}

Sender View:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="12.0" style="-fx-border-color: darkgrey; -fx-border-width: 2;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Label text="Sender">
         <font>
            <Font name="System Bold" size="24.0" />
         </font>
      </Label>
      <TextField fx:id="textField" />
      <Button fx:id="sendButton" mnemonicParsing="false" text="send" />
   </children>
   <padding>
      <Insets bottom="12.0" left="12.0" right="12.0" top="12.0" />
   </padding>
</VBox>

Receiver View:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="12.0" style="-fx-border-color: darkgrey; -fx-border-width: 2;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <Label text="Receiver">
         <font>
            <Font name="System Bold" size="24.0" />
         </font></Label>
      <Label fx:id="messageLabel" />
    </children>
    <padding>
        <Insets bottom="12.0" left="12.0" right="12.0" top="12.0" />
    </padding>
</VBox>

For further reading:

http://www.oracle.com/technetwork/java/javafx/community/3rd-party-1844355.html

http://www.guigarage.com/2015/02/quick-overview-datafx-mvc-flow-api/

http://www.guigarage.com/2014/05/datafx-8-0-tutorials/

http://jacpfx.org/2014/11/03/JacpFX_DataFX_a_perfect_match.html

Passing Parameters JavaFX FXML