Reputation: 5198
I am new to JavaFX and trying to create an Confirmation Dialogbox. I know already that there is no real build in dialogbox in JavaFX so I created one myself like this:
@FXML
public void delBox() {
try {
Stage dialogStage = new Stage();
AnchorPane root = FXMLLoader.load(getClass().getResource("Dialog.fxml"));
Scene scene = new Scene(root);
dialogStage.setScene(scene);
dialogStage.showAndWait();
} catch(Exception e) {
e.printStackTrace();
}
}
It looks pretty good already, but what I dont understand is, how those two Stages can communicate with each other? I want to pass a String to the dialog which is than shown in the message, also when one of the buttons in the dialog window is clicked I wanna react to this in the accordingly.
Can anyone explain me how communication between the stages works?
btw: I use .FXML
files and controller classes.
Upvotes: 0
Views: 1993
Reputation: 311
<AnchorPane xmlns:fx="..." fx:controller="DialogController.fxml"> ... </AnchorPane>
FX Controller is a java file, so it has to be DialogController and the Controller's path should be included i.e,
fx:controller="applicationPackageName.DialogController"
The above mentioned fxml code does not work. It results in
javafx.fxml.LoadException
java.lang.InstantiationException
java.lang.NoSuchMethodException
Reason: The jvm looks for a class constructor with 0 parameters to build an instance. To overcome the error, the controller file needs to be loaded in the function coded in java:
loader.setController(new ControllerName(""));
To sum up (Working code):
FXML file:
<BorderPane id="background" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="240.0" prefWidth="320.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" >
<bottom>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Button onAction="#close" text="OK" />
</children>
</HBox>
</bottom>
<center>
<Label fx:id="messageLabel" />
</center>
</BorderPane>
Controller file:
public class PiPreferenceController {
private final String message ;
@FXML
private Label messageLabel ;
@FXML
void initialize() {
messageLabel.setText(message);
}
public PiPreferenceController(String message) {
this.message = message ;
}
@FXML
public void close() {
messageLabel.getScene().getWindow().hide();
}
}
Function:
void dialogPreferences() throws IOException {
Stage dialogStage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"PiPreference.fxml"));
loader.setController(new PiPreferenceController(""));
BorderPane root = (BorderPane) loader.load();
Scene scene = new Scene(root);
dialogStage.setScene(scene);
dialogStage.showAndWait();
}
Upvotes: 1
Reputation: 209319
You need a reference to the controller for the dialog. To do this, create an instance of FXMLLoader
instead of using the static FXMLLoader.load(URL)
method.
For example, suppose you have a class DialogController
, so your Dialog.fxml
looks like:
<AnchorPane xmlns:fx="..." fx:controller="DialogController.fxml">
...
</AnchorPane>
Then you can access the DialogController
in the delBox()
method above with
Stage dialogStage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("Dialog.fxml"));
AnchorPane root = (AnchorPane)loader.load();
DialogController controller = (DialogController) loader.getController();
Scene scene = new Scene(root);
dialogStage.setScene(scene);
dialogStage.showAndWait();
And now you can communicate between the two controllers. For example, in DialogController
you could define a message
property, and bind it to a Label
:
public class DialogController {
private final StringProperty message = new SimpleStringProperty("");
public void setMessage(String message) {
this.message.set(message);
}
public String getMessage() {
return message.get();
}
public StringProperty messageProperty() {
return message ;
}
@FXML
private Label label ;
public void initialize() {
label.textProperty().bind(message);
// ...
}
}
And then back in your delBox() method:
//... as before:
AnchorPane root = (AnchorPane)loader.load();
DialogController controller = (DialogController) loader.getController();
controller.setMessage("Hello World");
// ...
Similarly, you can define properties which are set when controls are pressed in the dialog itself, and either observe them or query them after the showAndWait() call.
There are a bunch of other similar techniques. Some examples:
https://github.com/james-d/Shared-Data-Controller/tree/master/src
https://github.com/james-d/Dialog-FXML-Example/tree/master/src
https://github.com/james-d/Nested-Controller-Example/tree/master/src/nestedcontrollerexample
Upvotes: 2