I am trying to build a GUI in JavaFX using FXML. To do so, I have a main FXML page, which consists of 3 custom components that I also created using FXML. Here is my code directory:
src
App.java
ui
MainView.java
CustomHeader.java
CustomBody.java
fxml
MainView.fxml
CustomHeader.fxml
CustomBody.fxml
controller
MainViewController.java
CustomHeaderController.java
CustomBodyController.java
App.java
package ui;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import model.main.TaskItem;
import java.time.LocalDateTime;
import java.util.ArrayList;
public class ProductivityTrackerApp extends Application {
public static Stage primaryStage;
public static final String TITLE = "App";
public static final double WIDTH = 520;
public static final double HEIGHT = 800;
public static void main(String[] args) {
launch(args);
}
public void setPrimaryStage(Stage primaryStage) {
this.primaryStage = primaryStage;
}
public static void setScene(Parent root) {
try {
Scene scene = new Scene(root, WIDTH, HEIGHT);
primaryStage.setTitle(TITLE);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
System.out.println("Failed to load new Scene!");
}
}
@Override
public void start(Stage primaryStage) throws Exception {
setPrimaryStage(primaryStage);
setScene(new MainView());
}
}
Main.fxml
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="controllers.MainController"
fx:id="root"
type="VBox">
<children>
<CustomHeader> </CustomHeader>
<CustomBody> </CustomBody>
</children>
</fx:root>
MainView.java
package ui;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.VBox;
import java.io.File;
import java.io.IOException;
public class MainView extends VBox {
private static final String FXML = "src/fxml/MainView.fxml";
private File fxmlFile = new File(FXML);
public MainView() {
this.load();
};
private void load() {
try {
FXMLLoader fxmlLoader = new FXMLLoader(fxmlFile.toURI().toURL());
fxmlLoader.setRoot(this);
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}
CustomHeader.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="controllers.CustomHeaderController"
minHeight="80.0" prefWidth="520.0" type="StackPane">
<BorderPane>
<left>
</left>
<center>
<Label text="App"/>
</center>
<right>
<Button text="Click here" onMouseClicked="#colorBody"/>
</right>
</BorderPane>
</fx:root>
CustomHeader.java
package ui;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.StackPane;
import java.io.File;
import java.io.IOException;
public class MainView extends StackPane {
private static final String FXML = "src/fxml/CustomHeader.fxml";
private File fxmlFile = new File(FXML);
public CustomHeader() {
this.load();
};
private void load() {
try {
FXMLLoader fxmlLoader = new FXMLLoader(fxmlFile.toURI().toURL());
fxmlLoader.setRoot(this);
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}
CustomBody.fxml
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="controllers.CustomBodyController"
type="StackPane">
<Rectangle width="240" height="240" StackPane.alignment = "CENTER"/>
</fx:root>
CustomBody.java
package ui;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.StackPane;
import java.io.File;
import java.io.IOException;
public class MainView extends StackPane {
private static final String FXML = "src/fxml/CustomBody.fxml";
private File fxmlFile = new File(FXML);
public CustomBody() {
this.load();
};
private void load() {
try {
FXMLLoader fxmlLoader = new FXMLLoader(fxmlFile.toURI().toURL());
fxmlLoader.setRoot(this);
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}
The controllers have no functionality yet. Hence, I haven't included them.
I want to introduce a feature such that an onClick action on the button in the CustomHeader component changes the color of the rectangle in the CustomBody component. However, since these components have separate controllers, I wonder if there is a way for me to access both of these controllers from the MainController (the controller of the parent component). Furthermore, if possible, are there any better suggestions for mediating the communication of two sibling components?