I was recently putting the finishing touches on a demo desktop application written in Java 8 using JavaFX. The UI consists of a single FXML file attached to a controller class. My next task was to add a nice looking About box - something better than an Alert. So, I created an About.fxml using JavaFX Scene Builder 2.0. I wanted to attach the About.fxml to the same application controller class I already had, so the About's OK button would dispatch its event there. That, apparently, was a mistake that caused much grief, because loading the About.fxml kept giving me a non-specific LoadException error. Postings at online help sites didn't seem to match my situation. Most of them dealt with file path problems to the user's FXML file, resulting in a NullPointerException, but my FXML is embedded within my application JAR file.
I eventually came to the conclusion that the FXMLLoader did not like loading a second FXML specifying the same controller class as my main FXML. So, how to load my About.fxml to get the result I wanted - its use of the same controller class?
Okay, here's what I did. First, I removed any reference to a controller in About.fxml. That meant I had to specify the controller some other way. Here's my code in the controller class handler for the About menu event:
// load the About box FXML document
javafx.fxml.FXMLLoader loader = new javafx.fxml.FXMLLoader(
MyMainApp.class.getResource("About.fxml"));
loader.setController(this); // set 'this' as its controller
Parent root = loader.load(); // load UI objects from the FXML document
It turns out the magic I needed was the "setController" method above. Specifying the controller class in the FXML file tries to create a new instance of the controller class, I assume, which must be the origin of my earlier LoadException error. So, without that, the above loads fine.
Once the UI was loaded into a root Parent object (above), then it was time to configure the About dialog just the way I wanted: modal, no extra window decorations (i.e. Utility), owned by the main window, always on top, and not resizable ...
// create the dialog stage and set up its attributes
javafx.stage.Window owner = MyMainApp.getStage().getScene().getWindow();
Stage dialog = new Stage();
dialog.initStyle(StageStyle.UTILITY);
dialog.initModality(Modality.WINDOW_MODAL);
dialog.initOwner(owner);
dialog.setAlwaysOnTop(true);
dialog.setTitle("About MyMainApp");
dialog.setResizable(false);
Lastly, it was time to show the dialog:
// create the scene and set onto the stage
Scene scene = new Scene(root);
dialog.setScene(scene);
dialog.sizeToScene();
dialog.showAndWait();
At that point, my nice About box with a title and the system close button pops up! The underlying main window cannot gain focus. When I press the About's 'OK' button, I then get its event callback in my same controller class, which then closes the About box:
@FXML
public void onButtonHelpAboutDismissAction(ActionEvent event)
{
Stage stage = (Stage)buttonHelpAboutDismiss.getScene().getWindow();
stage.close();
}
Now, I'm sure there's a stupidly simpler way to do this in JavaFX, but I didn't see any other online examples for an About box like this. So, this is my contribution, as a relative Java newbie.
Any comments?