JavaFX Modal Dialog with a controller class
There are quite a few tutorials out there detailing how to
produce a modal dialog with JavaFX. Jewelsea gives an excellent example on https://gist.github.com/jewelsea/1887631
and I recommend that you read it.
However none that I've found seem to show you how to do it
using controller classes and separate JavaFX FXML dialogs. Admittedly I've not
looked that hard but hopefully this will help someone.
Prerequisites
1.
Java SDK – which at the time of writing is
located here - http://www.oracle.com/technetwork/java/javase/downloads/index.html
2.
JavaFX – this is included in the SDK.
3.
JavaFX SceneBuilder – found here http://www.oracle.com/technetwork/java/javafx/tools/index.html
I assume that if you’re reading this then you already have
the above.
Method
I’ve used NetBeans to create this example. It doesn’t matter
particularly but it does show. Anyway, firstly, create a new FXML project. I’ve
called mine JavaFXTest with the controller named Test.
Modify the code so that it looks like the following:
-----------------------------------------------------------------
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* Demonstrates a modal dialog with controller
class
*/
public class JavaFXTest extends Application {
@Override
public
void start(Stage stage) throws
Exception {
FXMLLoader fl = new FXMLLoader();
fl.setLocation(getClass().getResource("Test.fxml"));
fl.load();
Parent root = fl.getRoot();
TestController tc = (TestController)fl.getController();
tc.setStage(stage);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* The main() method is ignored in
correctly deployed JavaFX application.
* main() serves only as fallback in case
the application can not be
* launched through deployment artifacts,
e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* @param args the command line arguments
*/
public
static void main(String[] args) {
launch(args);
}
}
-----------------------------------------------------------------
NetBeans will also create a FXML file with one button and a controller
class. The code for the controller class will need to be modified to look like this:
-----------------------------------------------------------------
import
java.io.IOException;
import
java.net.URL;
import
java.util.ResourceBundle;
import
javafx.event.ActionEvent;
import
javafx.fxml.FXML;
import
javafx.fxml.FXMLLoader;
import
javafx.fxml.Initializable;
import
javafx.scene.Parent;
import
javafx.scene.Scene;
import
javafx.stage.Modality;
import
javafx.stage.Stage;
import
javafx.stage.StageStyle;
/**
*
* This is the main controller class
*/
public
class TestController implements Initializable {
private Stage primaryStage;
@FXML
private void handleButtonAction(ActionEvent
event) throws IOException {
System.out.println("You clicked
me!");
FXMLLoader fl = new FXMLLoader();
fl.setLocation(getClass().getResource("Test1.fxml"));
fl.load();
Parent root = fl.getRoot();
Stage modal_dialog = new
Stage(StageStyle.DECORATED);
modal_dialog.initModality(Modality.WINDOW_MODAL);
modal_dialog.initOwner(primaryStage);
Scene scene = new Scene(root);
Test1Controller t1 =
(Test1Controller)fl.getController();
t1.setStage(modal_dialog);
modal_dialog.setScene(scene);
modal_dialog.show();
}
public void setStage(Stage temp){
primaryStage = temp;
}
@Override
public void initialize(URL url,
ResourceBundle rb) {
// TODO
}
}
-----------------------------------------------------------------
Essentially all we’ve done here is pass a reference to
the primary Stage object to the main controller class. The only tricky bit (because
it’s not documented well) is to use an FXMLLoader class to load the initial FXML
dialog and get the controller.
Once this is done you can use the same method to create a
new FXML dialog. This time a modal one. Make the owner of the modal dialog the
initial stage. Then pass a reference to the newly created modal dialog to the
modal dialog controller class, which we now create.
So the next step is to create another FXML file within
the project. Right click on the project and select an empty FXML file. Call the
controller class Test1. Once created, the code should be changed to this:
-----------------------------------------------------------------
import
java.net.URL;
import
java.util.ResourceBundle;
import
javafx.event.ActionEvent;
import
javafx.fxml.FXML;
import
javafx.fxml.Initializable;
import
javafx.stage.Stage;
/**
* FXML Controller class
*
* This is the modal dialog
*/
public
class Test1Controller implements Initializable {
private Stage parentStage;
@FXML
private void handleButtonAction(ActionEvent
event) {
System.out.println("You clicked me
2!");
parentStage.close();
}
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url,
ResourceBundle rb) {
// TODO
}
public void setStage(Stage temp){
parentStage = temp;
}
}
---------------------------------------------------------------------------------
In the FXML file create a button and associate it with the
handleButtonAction handler.
As you can see the Stage object used to create the dialog is
passed to the controller. Within the controller you then use the handler to take
any actions, update objects and close the dialog.
It isn't pretty (much like this blog), but it does work.
Useful, thanks
ReplyDeletethank you! I've been researching this for days with no luck
ReplyDelete