Continue program execution after showAndWait javafx - javafx

Hello I have a procedure who load a stage like this :
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource(ConstantsUI.CHEMIN_VIEW+
ConstantsUI.ECRAN_CAISSE_FERMEE));
AnchorPane ecran = (AnchorPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(ecran);
MainApp.getInstance().getPrimaryStage().setScene(scene);
genericController = loader.getController();
genericController.setStage(MainApp.getInstance().getPrimaryStage());
// on garde la fenĂȘtre en premier plan
MainApp.getInstance().getPrimaryStage().setMaximized(true);
MainApp.getInstance().getPrimaryStage().show();
MainApp.getInstance().getPrimaryStage().showAndWait();
System.out.println("toto");
And I have an button with this code :
#FXML
public void clickButton() {
System.out.println("------here-----");
stage.close();
}
My problem is, that after I clicked on my button, the message "toto" is not visible. Why ?
Thanks.

Calling showAndWait is not allowed for the primary stage.
From the javadoc
Throws:
[...]
IllegalStateException - if this method is called on the primary stage.
You could instead use a onHidden event handler:
MainApp.getInstance().getPrimaryStage().setOnHidden(evt -> {
System.out.println("toto");
});
MainApp.getInstance().getPrimaryStage().show();
Alternatively if you want to run the code after the last window of the application has been closed (asumming you didn't use Platform.setExplicitExit(false)), you could override Application.stop():
#Override
public void stop() throws Exception {
System.out.println("toto");
}

Related

JavaFX FXMLLoader getController NullPointerException

I have a project in school where I have to develop a program where you first can choose whether you want to save/read to/from a SQL DB or to save/read to/from XML.
I've made a GUI where you can choose between both methods.
The GUI closes after the user clicks on one of the buttons and the MainMenu GUI opens.
Now I need to know in the MainMenuController what the user choose.
I found online a Method to call the MainMenuController inside the first controller, with FXMLLoader.getController().
try {
Stage stage = new Stage();
FXMLLoader Loader = new FXMLLoader();
Parent root = Loader.load(getClass().getResource("MainMenu.fxml"));
MainMenuController mc = Loader.getController();
mc.setSave("sql");
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
catch (Exception e) {
e.printStackTrace();
}
MainMenuController
public class MainMenuController {
private String save = null;
public void setSave(String save) {
this.save=save;
}
public String getSave() {
return save;
}
}
But when i try to access a method in MainMenuController I get a NullPointerException for
mc.setSave("sql")
First ,to understand this issue ,you should make some tricks to detect where is your problem.When you do :
System.out.println(mc);
You will find the result is null.So you can not call setSave("sql") with null object,you got a null controller because your did not specify the location of your file,but you can change some lines to resolve your problem :
try {
Stage stage = new Stage();
FXMLLoader fxm = new FXMLLoader(getClass().getResource("MainMenu.fxml"));
Parent parent = (Parent) fxm.load();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
FirstController mc = fxm.getController();
System.out.println(mc);
mc.setSave("sql");
} catch (Exception e) {
e.printStackTrace();
}
You are calling the static method FXMLLoader.load(URL). Because this is a static method, it has no effect on the state of the FXMLLoader instance you created; specifically the controller field is not set.
Instead, set the location on the FXMLLoader instance, and call the instance method load():
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("MainMenu.fxml"));
// or just FXMLLoader loader = new FXMLLoader(getClass().getResource("MainMenu.fxml"));
Parent root = loader.load();

How can I use .setText on a non-Static Label from a different Class [duplicate]

I have written a controller for two windows /stages.
The first window is opened in the MainClass. The second in the Controller, if the user clicks onto a button.
How can I get the TextFields from second.fxml in the applyFor()-method?
Thanks.
#FXML
protected void requestNewAccount(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("second.fxml")); // TextFields in there
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Second Window");
Scene scene = new Scene(root);
String css = MainOnlineCustomer.class.getResource("/style.css").toExternalForm();
scene.getStylesheets().clear();
scene.getStylesheets().add(css);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
logger.error(e);
}
}
/**
* closes the "second"-Window
* #param event
*/
#FXML
protected void cancel(ActionEvent event) {
final Node source = (Node) event.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
#FXML
protected void applyFor(ActionEvent event) {
// get values from TextField in second.fxml here!!!
}
It's not good to share controllers between fxmls unless they serve the same purpose. Here both fxml seem to serve a different purpose (account management, login or something similar for one of them and creating a new account for the other). What is even worse is that those classes do not share the same controller instance, which means the small (and probably only) benefit you could get from using the same controller, is not used here. You should better use different controllers.
Since you use Modality.APPLICATION_MODAL as modality, I'd recommend using showAndWait instead of show to open the new stage. This will enter a nested event loop, which allows the UI to remain responsive and continues after the invocation of showAndWait once the stage is closed.
Furthermore add a method to the controller of second.fxml that allows you to retrieve the result.
Example
This creates a Person object with given name and family name.
"primary window (opening the "inner" stage)
FXMLLoader loader = new FXMLLoader(getClass().getResource("second.fxml"));
Stage subStage = new Stage();
subStage.initModality(Modality.APPLICATION_MODAL);
subStage.setTitle("Second Window");
Scene scene = new Scene(loader.load());
subStage.setScene(scene);
subStage.showAndWait();
Optional<Person> result = loader.<Supplier<Optional<Person>>>getController().get();
if (result.isPresent()) {
// do something with the result
}
controller for "inner" content
public class SecondController implements Supplier<Optional<Person>> {
#FXML
private TextField givenName;
#FXML
private TextField familyName;
private boolean submitted = false;
// handler for submit action
#FXML
private void submit() {
submitted = true;
givenName.getScene().getWindow().hide();
}
// handler for cancel action
#FXML
private void cancel() {
givenName.getScene().getWindow().hide();
}
#Override
public Optional<Person> get() {
return submitted ? Optional.of(new Person(givenName.getText(), familyName.getText())) : Optional.empty();
}
}
Note that you can gain access to any data available to the controller this way. I wouldn't recommend accessing any nodes (like TextFields) directly though, since this makes changing the UI harder.
Using the Supplier interface here is not necessary, but I chose to do this to achieve a loose coupling between SecondController and the main window.

JavaFX how to close stage to act the same way the 'x' button in the window

I have a controller that opens a new stage as a popup:
#FXML
private void onClickPayments(ActionEvent event) throws IOException{
FXMLLoader loader = new FXMLLoader(getClass().getResource("ClientPayments.fxml"));
Parent root = (Parent) loader.load();
ClientPaymentsController controller = (ClientPaymentsController) loader.getController();
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.setOnCloseRequest((WindowEvent we) -> {
clientBLL.retrieve(clientID);
updateWarning();
});
stage.show();
controller.setClientID(clientID);
}
When the other stage is closed by the 'x' button the 'stage.setOnCloseRequest' is executed. But in that stage I have a button to close:
#FXML
private void onClickExit(ActionEvent event){
((Stage) ((Node) event.getSource()).getScene().getWindow()).close();
}
It closes, but the method 'stage.setOnCloseRequest' isn't being executed.
Is this method wrong or is there a way to close a popup in a way that acts exactly like the 'x' button in the window?
The setOnCloseRequest handler is executed when there is an external request to close the window (i.e. not one from your code). See the documentation.
If it's enough to execute that logic immediately after the window is closed, just use the regular onHidden handler instead:
stage.setOnHidden((WindowEvent we) -> {
clientBLL.retrieve(clientID);
updateWarning();
});
If you really need to use the onCloseRequest handler (e.g. because you might want to veto the close), just move your close logic to a method and invoke it from both types of request to close the window.
public void doClose() {
clientBLL.retrieve(clientID);
updateWarning();
}
#FXML
private void onClickExit(ActionEvent event){
doClose();
((Node) event.getSource()).getScene().getWindow().hide();
}
and
stage.setOnCloseRequest((WindowEvent we) -> {
controller.doClose();
});

Issues with MouseControl in a different fxml using javafx

I am sorry to ask this silly question. I am unable to solve it and I need guidance.
In my application I start my main java code with menu as
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("MONC GUI :: Abhijit Bhattacharyya");
FXMLLoader loader = new FXMLLoader(MoncGUI.class.getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
//Scene scene = new Scene(rootLayout);
rootScene = new Scene(rootLayout);
primaryStage.setScene(rootScene);
RootLayoutController controller = loader.getController();
controller.setMainApp(this);
primaryStage.show();
}
......
Then I opt to go to a particular menu page by opening another fxml in the main class as
public void GeomStart() {
try {
FXMLLoader loader = new FXMLLoader(MoncGUI.class.getResource("Geom.fxml"));
AnchorPane geomPage = (AnchorPane)loader.load();
rootLayout.setCenter(geomPage);
GeomController controller = loader.getController();
controller.setMyScene(rootScene);
} catch (IOException ex) {
System.out.println(" Problem in loading geometry set");
Logger.getLogger(MoncGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
The geom.fxml is associated with geomController.java which puts a primitive geometric form on the screen and I want it to be rotated. I find mouseHandler code in the internet which should be activated as screen is passed.
I am confused which screen should I pass. Is it the root screen initiated by the main class at the start or I need to define a new screen locally here in this controller. I tried with a screen local to this controller yet the code handle is not passed to MouseHandler code.
Thanks and Regards
There is no need to pass the scene arround at all. Inside your controller you have access to the nodes which you have defined in your FXML file. Once this file is loaded and you have attached its root node to the scene graph you can get the scene by calling the .getScene() method of any of these nodes.

[A]How to use setFullScreen methode in javafx?

I have a stage with these properties
stage = new Stage(StageStyle.DECORATED);
stage.setFullScreen(true);
stage.setFullScreenExitHint("");
stage.setTitle("My App");
stage.getIcons().add(new Image(icon-address));
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("start.fxml"));
fxmlLoader.setController(this);
...
...//and other properties
It is in full screen in this stage. I have a button and each time I click on it , a method of another class is called and the reference of this stage is passed to it.
For example, if I have two classes Start and ButtonClicked
In Start, I have this :
Button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
buttonClicked a = new buttonClicked ();
try {
a.render(stage);
} catch (Exception ex) {
Logger.getLogger(menuController.class.getName())
.log(Level.SEVERE, null , ex);
}
}
});
Now, the render method is called and I have the following code inside render :
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("buttonclicked.fxml"));
fxmlLoader.setController(this);//set Controller for our fxml file
loader = fxmlLoader.load();//loader is a stackPane because buttonclick.fxml has stackPane
stage.setScene(new Scene(loader));
stage.setFullScreen(true);
...
The problem is, if user clicks on button, stage become a 1024x700(because i have pictures in start.fxml and buttonclicked.fxml. The size of both the picture is 1024x700
After a moment, it becomes full screen. How can i fix this ?
I want to kill the delay in full screen
Thanks
Try
stage.getScene().setRoot(loader);
in render method.
By doing this, the creation of a new scene is eliminated. Therefore I guess, some UI related updates and calculations that must be done after the scene has been shown, are also eliminated.

Resources