I'm having problem to close my javaFX application, when I click the close button from my stage, my application disappears but if I look for it in my task manager my application still there without close.
I've tried to use this code below to force it close the main thread and all childrens threads but the problem persists.
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
Platform.exit();
}
});
Does your application spawn any child threads? If so have you ensured that you terminate them (assuming that they're not daemon threads)?
If your application spawns non-daemon threads then they (and therefore your app) will continue to live on until such time you kill the process
The only way was to call System.exit(0);
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
Platform.exit();
System.exit(0);
}
});
[EDITED]
System.exit will just hide your application, if you open SO's manager task your application will be there. The correct way is to check your Threads, one by one and close all before close application.
First Look Here
public void start(Stage stage) {
Platform.setImplicitExit(true);
stage.setOnCloseRequest((ae) -> {
Platform.exit();
System.exit(0);
});
}
I currently had this problem while using an ThreadExecutor in the controller.
Application does not exit if the ThreadExecutor is not shutdown.
See here:
how-to-shut-down-all-executors-when-quitting-an-application
As it can be a problem to recognize an application exit in the controller, you can get a reference to the controller from your Application class like so (using the sample application from Eclipse):
public class Main extends Application {
private SampleController controller;
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml"));
BorderPane root = (BorderPane)loader.load(getClass().getResource("Sample.fxml").openStream());
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
controller = loader.<SampleController>getController();
}
catch(Exception e)
{
e.printStackTrace();
}
}
Your Application overrides the stop method, where you can call a housekeeping method of the controller (i use a method called startHousekeeping):
/**
* This method is called when the application should stop,
* and provides a convenient place to prepare for application exit and destroy resources.
*/
#Override
public void stop() throws Exception
{
super.stop();
if(controller != null)
{
controller.startHousekeeping();
}
Platform.exit();
System.exit(0);
}
I was able to fix this problem by calling com.sun.javafx.application.tkExit(). You can read more in my other answer here: https://stackoverflow.com/a/22997736/1768232 (these two questions really are duplicates).
Just a note:
Try checking if you use
Platform.setImplicitExit(false);
Had a similar problem and overflowing my tasks. The above line will not make the stage close, it will hide it.
To imitate pressing 'x' one can do:
stage.fireEvent(new WindowEvent(stage, WindowEvent.WINDOW_CLOSE_REQUEST))
Related
I'm working on a game in JavaFX, and right now I'm trying to create a loading screen, since loading the assets takes some time. I've created a LoadingPane class that displays several progress bars, and I know for sure that it works. However, in the below code, the loading pane will not be visible until after the loadAssets function, even though I'm adding it beforehand. When I run the below code, I get a blank stage for the time it takes for the assets to load, and then a screen with the completed progress bars.
I haven't been able to find anyone with similar issues, or any sort of refresh or update function to force the scene to display the loading pane before continuing with the program.
Note: I've deleted some irrelevant code setting up keyboard input handling.
public class Main extends Application{
Pane root = new Pane();
Scene mainScene = new Scene(root, Constants.WINDOW_WIDTH, Constants.WINDOW_HEIGHT, Color.BLACK);
static LoadingPane loadingPane = new LoadingPane(3);
private static int loadingIndex = 0;
public static void main(String[] args) {
if(Constants.DEBUG_MODE)
System.out.println("WARNING: Game has launched in debug mode!");
launch(args);
}
public static void updateProgress(double percent){
loadingPane.setBarLength(loadingIndex, percent);
}
public static void loadAssets(){
RoomLoader.createRooms();
updateProgress(1.0);
loadingIndex++;
ProjectileLoader.load("imgs/projectiles/");
ProjectileLoader.load(Constants.BATTLE_IMAGES_FILEPATH);
updateProgress(1.0);
loadingIndex++;
BattleLoader.createBattles();
updateProgress(1.0);
loadingIndex++;
}
public static void updateProgress(double percent){
loadingPane.setBarLength(loadingIndex, percent);
}
#Override
public void start(final Stage primaryStage) {
//root.getChildren().add(new javafx.scene.image.ImageView(new Image("imgs/loading.png")));
root.setLayoutX(0);
primaryStage.setScene(mainScene);
primaryStage.show();
primaryStage.toFront();
primaryStage.setTitle("Branch");
primaryStage.setResizable(false);
//primaryStage.getIcons().add(new Image("core/imgs/soul/red.png"));
//This allows the closing of the primaryStage to end the program
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>(){
#Override
public void handle(WindowEvent t) {
System.exit(0);
}
});
root.resize(Constants.WINDOW_WIDTH, Constants.WINDOW_HEIGHT);
primaryStage.getIcons().add(new Image("imgs/icon.png"));
//End GUI setup
//The problem lines
root.getChildren().add(loadingPane);
//refresh root?
loadAssets();
}
}
EDIT: Working Code
For anyone who arrives here with a similar issue, below is the code I used to get this to work:
I replaced this:
//The problem lines
root.getChildren().add(loadingPane);
//refresh root?
loadAssets();
With this:
root.getChildren().add (loadingPane);
Task<Integer> loadingTask = new Task<Integer>() {
#Override protected Integer call() throws Exception {
loadAssets();
return 1;
}
};
loadingTask.setOnSucceeded(new EventHandler<WorkerStateEvent>(){
#Override
public void handle(WorkerStateEvent t){
loadingPane.setVisible(false);
load(); //note: this function sets up the actual game
//updating the GUI, adding game elements, etc
}
});
new Thread(loadingTask).start();
I can't say that this is the best way to go about this, but I can say that it works. Good luck!
You need a separate thread for the update method.
Code runs in a linear fashion, one bit of code runs then the next. With a separate thread, the two “lines” of code can run side by side. The process runs and the GUI updates at the same time.
JavaFX application runs on specific thread called Application Thread, in other to make GUI responsive while doing some expensive operation, like in your case loading assets, you will need to load assets on another Thread that you create yourself or you can use Task which is one of JavaFX classes meant to be used in such use cases.
I suggest you to read about Task in official javadocs
How can I close my JavaFX application after showing the error in a dialog?
In main:
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent we) {
logger.debug("Tool is closing...");
JDBCUtil.closeConnection(); // necessary
}
});
In another class :
// ... creating Dialog, Alert, etc.
Optional<ButtonType> result = exception.showAndWait();
if (result.get().getButtonData() == ButtonData.CANCEL_CLOSE) {
Platform.exit(); // but the handle method isn't called then...
}
Although setOnHiding() event will be handled, setOnCloseRequest() will not be called when application level shutdown has been detected (Platform.exit() has been called).
This is not connected to the stage, so even if you add setOnCloseRequest() in your dialog stage, it wouldn't be called.
Those kind of stage level methods (e.g. setOnCloseRequest, setOnCloseRequest) are not the correct methods to detect and process application level shutdown event. Instead, you should implement stop() from Application, to detect application shutdown, and handle needed actions.
So in your primary application,
#Override
public void stop() throws Exception {
JDBCUtil.closeConnection();
super.stop();
}
I have created a JavaFX application, and noticed that after I close the main stage, the following happens:
The Applications "stop" method is called
The main method continues
After the program leaves the main method, the JVM can not close
I do not create any threads (explicitly not, at least). The threads that are running at this point are (from the debug console):
InvokeLaterDispatcher
Prism Font Disposer
'pool-2-thread-1' (I don't know what this is - ThreadPoolExecutor parts are in its stacktrace)
HSQLDB Timer (I'm using a HSQLDB file db on the development/debug system)
FX Access Thread (Visual Debugger)
Abandoned connection cleanup thread
Which of these threads can stop the JVM from closing? I would think that all of these should be daemon threads...
Here is my Application code:
public class MainApp extends Application {
#Override
public void start(Stage stage) throws Exception {
final FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/Main.fxml"));
Parent root = fxmlLoader.load();
Scene scene = new Scene(root);
scene.getStylesheets().add("/styles/Styles.css");
//... Scene/stage setup here
stage.show();
}
#Override
public void stop() throws Exception {
super.stop();
}
public static void main(String[] args) {
launch(args);
}
}
Adding a System.exit(0); on the end of the stop() method fixes this, but I'm not sure if this is the best solution to the problem...
Any ideas?
Thx in advance
You say you are using a HSQLDB, you don't show the code where you initialize it. In your stop() method, close that connection.
As the title says, my question is, how can I prevent/cancel closing of primary stage in JavaFX 2.2? I have done some research on Google, and the following two links seemed to address the issue:
Prevent or cancel exit JavaFX 2
Thread: JavaFX 2.0 Stage onClose event
I tried the methods explained by those two links, but sadly for me, none of them works. So, without further ado, here is what I had done.
Firstly, I tried to attach an OnCloseRequest to the primaryStage as follows.
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
if (!canExit()) {
event.consume();
primaryStage.show(); // I tried without this line also.
}
}
});
When canExit() returns false, I tried to prevent the event from propagating further and cause to exit the app by callingevent.consume(). But the stage is getting closed/hidden and I got the following error messages on Netbeans output window. It keeps coming repeatedly until I force close the app from Netbeans.
(java:6731): Gtk-CRITICAL **: IA__gtk_widget_get_visible: assertion `GTK_IS_WIDGET (widget)' failed
(java:6731): Gtk-CRITICAL **: IA__gtk_widget_get_visible: assertion `GTK_IS_WIDGET (widget)' failed
(java:6731): Gtk-CRITICAL **: IA__gtk_widget_get_visible: assertion `GTK_IS_WIDGET (widget)' failed
Having tasted failure in this attempt, I changed OnCloseRequest to OnHiding with the expectation of success.
primaryStage.setOnHiding(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
if (!canExit()) {
event.consume();
primaryStage.show(); // I tried without this line also.
}
}
});
Although, I tasted failure in this attempt too, I think I have made some progress. There is no error messages this time, and no need to force close the application from Netbeans.
Then I read about some magic method named setImplicitExit() in the Platform class. Thinking that this is what I was missing, I tried Platform.setImplicitExit(false); with both of the two methods as follows:
OnCloseRequest version
Platform.setImplicitExit(false);
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
if (!canExit()) {
// ...
} else {
Platform.exit();
}
});
No difference, the stage gets closed/hidden, and the same error message comes repeatedly.
OnHiding version
Platform.setImplicitExit(false);
primaryStage.setOnHiding(new EventHandler<WindowEvent>() {
if (!canExit()) {
// ...
} else {
Platform.exit();
}
});
Beginning on a positive note, the application doesn't get exited as earlier. But, the negative note is that the stage is still getting closed/hidden.
Now, I am out of weapons/equipments in my armoury to solve it, and so I am here to request the help of you heroes and champions. So, How can I solve this problem or what have I done wrong or what am I missing?
I have used following code in my application and it works perfectly,
Platform.setImplicitExit(false);
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
event.consume();
}
});
I think this is a bug with JavaFX for Linux. I ran in to the same problem on Javafx 2.2.21-b11. Depending on the context the GTK errors may or may not be present, but either way consuming the close request event didn't prevent the window from closing (yet the process continues to run). The same app on Windows behaved as I would expect. So at best we have a difference in behavior across platforms.
I filed a bug report you can upvote if you'd like: https://javafx-jira.kenai.com/browse/RT-33295
Here's the source of my test app
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class Boom extends Application {
#Override
public void start(final Stage primary) {
System.out.println(com.sun.javafx.runtime.VersionInfo.getRuntimeVersion());
primary.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent e) {
e.consume();
}
});
primary.show();
}
public static void main(String[] args) {
launch(args);
}
}
I think you got the onCloseRequest() concept wrong. If you consume the event you cancel the closing! So it works the other way round, if canExit() returns false you consume the event
That worked for me
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
AlertHelper addMore = new AlertHelper("Exit application? Any unsaved data will be lost", "Attention", "Confirmation Required");
boolean actionNeeded = addMore.populatePopup();
if (actionNeeded) {
System.exit(0);
} else {
event.consume();
}
}
});
I am making a desktop application which has login and logout functionality with server.
I need to logout from the application whenever someone close the window, so I am using these codes
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
event.consume();
closeWindow();
}
});
where closeWindow() contains logout and other related steps.
Now there is a problem when application closes unexpectedly or when someone forcefully quit/close it from Task Manager (by ending process).
Do JavaFX has any event to capture forcefully quit or unexpected close ? Or if there any method to stop it ?
When your application gets closed via TaskManager your only option will be to use the VM's shutdown hook.
There are some examples around, e.g. here.
There is a method
#Override
public void stop() throws Exception {
super.stop();
System.out.println("logout");
}
in Application class.
public class Gui extends Application {
static {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
closeWindow();
}
});
}
#Override
public final void start(Stage primaryStage) throws Exception {
// ...
}
#Override
public void stop() throws Exception {
// ...
System.exit(0);
}
}
If you are using a task for that logout procedure, try playing with setDaemon method. I solved a similar case by showing a "loading" window and closing that window after the task completes. You can try that too.