How to close a JavaFX application on window close? - java

In Swing you can simply use setDefaultCloseOperation() to shut down the entire application when the window is closed.
However in JavaFX I can't find an equivalent. I have multiple windows open and I want to close the entire application if a window is closed. What is the way to do that in JavaFX?
Edit:
I understand that I can override setOnCloseRequest() to perform some operation on window close. The question is what operation should be performed to terminate the entire application?
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
stop();
}
});
The stop() method defined in Application class does nothing.

The application automatically stops when the last Stage is closed. At this moment, the stop() method of your Application class is called, so you don't need an equivalent to setDefaultCloseOperation()
If you want to stop the application before that, you can call Platform.exit(), for example in your onCloseRequest call.
You can have all these information on the javadoc page of Application : http://docs.oracle.com/javafx/2/api/javafx/application/Application.html

Some of the provided answers did not work for me (javaw.exe still running after closing the window) or, eclipse showed an exception after the application was closed.
On the other hand, this works perfectly:
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
Platform.exit();
System.exit(0);
}
});

For reference, here is a minimal implementation using Java 8 :
#Override
public void start(Stage mainStage) throws Exception {
Scene scene = new Scene(new Region());
mainStage.setWidth(640);
mainStage.setHeight(480);
mainStage.setScene(scene);
//this makes all stages close and the app exit when the main stage is closed
mainStage.setOnCloseRequest(e -> Platform.exit());
//add real stuff to the scene...
//open secondary stages... etc...
}

stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.exit();
System.exit(0);
}
});

Did you try this..setOnCloseRequest
setOnCloseRequest(EventHandler<WindowEvent> value)
There is one example

Instead of playing around with onCloseRequest handlers or window events, I prefer calling Platform.setImplicitExit(true) the beginning of the application.
According to JavaDocs:
"If this attribute is true, the JavaFX runtime will implicitly
shutdown when the last window is closed; the JavaFX launcher will call
the Application.stop() method and terminate the JavaFX
application thread."
Example:
#Override
void start(Stage primaryStage) {
Platform.setImplicitExit(true)
...
// create stage and scene
}

Using Java 8 this worked for me:
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Region());
stage.setScene(scene);
/* ... OTHER STUFF ... */
stage.setOnCloseRequest(e -> {
Platform.exit();
System.exit(0);
});
}

For me only following is working:
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.exit();
Thread start = new Thread(new Runnable() {
#Override
public void run() {
//TODO Auto-generated method stub
system.exit(0);
}
});
start.start();
}
});

This seemed to work for me:
EventHandler<ActionEvent> quitHandler = quitEvent -> {
System.exit(0);
};
// Set the handler on the Start/Resume button
quit.setOnAction(quitHandler);

Try
System.exit(0);
this should terminate thread main and end the main program

getContentPane.remove(jfxPanel);
try it (:

in action button try this :
stage.close();
exemple:
Stage stage =new Stage();
BorderPane root=new BorderPane();
Scene scene=new Scene();
Button b= new Button("name button");
b.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
stage.close();
}
});
root.getChildren().add(b);
stage.setTitle("");
stage.setScene(scene);
stage.show();

You MUST override the "stop()" method in your Application instance to make it works. If you have overridden even empty "stop()" then the application shuts down gracefully after the last stage is closed (actually the last stage must be the primary stage to make it works completely as in supposed to be).
No any additional Platform.exit or setOnCloseRequest calls are need in such case.

Related

JAVAFX - How to call a method on launch of the application

I'm new when it comes to JavaFX. But I really wanna learn. I'm I know how to call methods using ActionEvent, but what if I have a method that I want to call as soon as I launch the application? Normally the methods only get executed, when you perform an action, like pressing a button, but in this case I just want to run it along with the startup. Could anyone help here?
Just call the method you want to call in the start method of your application.
public class Main extends Application {
#Override
public void init() {
//you can call your method here but if you
//plan on doing stuff to the stage call it in the start method
}
#Override
public void start(Stage stage) throws Exception {
// call your method here
myMethod();
//show the application
BorderPane pane = new BorderPane();
Scene scene = new Scene(pane);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
public void myMethod() {
//do Stuff
}
}
You can call the method inside the init() method but you can't do stuff to the stage or scene.

JavaFX KeyEvents during Drag & Drop operation

I need to know whether a certain key is down while performing a drag & drop operation.
So I tried to use setOnKeyPressed / setOnKeyReleased of a Scene with a combination of HashMap, but I have a problem with this approach:
Imagine a scenario that one drags & drops a TableView item to somewhere while holding Control down. Now if I display a dialog at the end of the drop, while still holding Control down, the setOnKeyReleased is never called with this approach... as the Dialog is the one receiving the key released event.
How could I fix this?
Hope I understand your question here is a possible solution(work with any key):
public class Main extends Application {
SimpleBooleanProperty isKeyPress = new SimpleBooleanProperty(false);
#Override
public void start(Stage primaryStage) throws Exception{
Parent window = new VBox();
((VBox) window).getChildren().add(new Label("example of small window:"));
primaryStage.setTitle("example");
Scene scene=new Scene(window);
primaryStage.setScene(scene);
primaryStage.show();
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
System.out.println("Press");
isKeyPress.set(true);
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Information Dialog");
alert.setHeaderText(null);
alert.setContentText("I have a great message for you!");
Scene alertScene = alert.getDialogPane().getScene();
alertScene.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
System.out.println("Released on dialog");
isKeyPress.set(false);
}
});
alert.showAndWait();
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
System.out.println("Released");
isKeyPress.set(false);
}
});
}
public static void main(String[] args) {
launch(args);
}
}
output exmple:
Press
Released on dialog
From your comment the goal is to change the behavior of the drag and drop depending on whether or not Ctrl is down. When it is do a copy operation, otherwise do a move operation. You do not need to deal with KeyEvents to implement this behavior. Instead, you would determine whether to copy or move in the onDragDetected handler. The onDragDetected handler uses a MouseEvent which has methods for querying the status of modifier keys—such as isControlDown(). Using this, we can specify what transfer modes are allowed based on the modifier keys.
Node node = ...;
node.setOnDragDetected(event -> {
Dragboard board;
if (event.isControlDown()) {
board = node.startDragAndDrop(TransferMode.COPY);
} else {
board = node.startDragAndDrop(TransferMode.MOVE);
}
// add contents to Dragboard
});
Note it may be more cross-platform to use isShortcutDown().

JavaFX - Block user from changing stages without using MODAL

I have an application that looks like the following:
When a user clicks on the deck of cards, it opens up a new Stage.
This stage can be closed in one of two ways:
Right click the stage.
Click outside of the stage (it has a evenhandler for when it loses focus).
However, sometimes I NEED the user to select one or more cards from the deck using this window. I do not want to allow him to close the window until he has selected at least one card. This means I had to use MODAL to stop him from being able to access the stage underneath (My Applicaiton). The problem with MODAL is now he can never leave the window like he could before by clicking outside the stage, even when I want him to be able to. He is now only able to leave through right clicking. I could add a button but I'd really rather not.
I hope I explained my problem well enough. What would you guys recommend I do? Is there a way I could somehow block the user from going back to the previous stage without MODAL? I'm also not able to change Modality after the Stage has been shown, so that won't work.
Thanks!
The idea is to use the onCloseRequestProperty property of your pop-up Stage.
Called when there is an external request to close this Window. The
installed event handler can prevent window closing by consuming the
received event.
With this property you can interrupt the closing of the Stage if a condition (in your case at lest one card is selected) is not met by calling consume on the WindowEvent.
Note: As the documentation states: it is only valid if the request is external, so if you call the close method of the Stage, the attached listener will be not executed. As a solution rather than calling this method you can fire the WindowEvent.WINDOW_CLOSE_REQUEST event manually.
Example:
public class PopUpApp extends Application {
Stage popupStage;
Stage primaryStage;
#Override
public void start(Stage stage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 400, 400);
primaryStage = stage;
initPopUpStage();
// When the Pop-Up stage is showing, do not handle any action on the
// main GUI
root.disableProperty().bind(popupStage.showingProperty());
Button b = new Button("Open deck");
b.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// Add some ToggleButtons to simulate the cards
VBox vbox = new VBox();
vbox.setAlignment(Pos.CENTER);
List<ToggleButton> toggles = new ArrayList<ToggleButton>();
for (int i = 0; i < 4; i++) {
ToggleButton tb = new ToggleButton("Card " + i + 1);
toggles.add(tb);
}
vbox.getChildren().addAll(toggles);
Scene sc = new Scene(vbox, 300, 300);
popupStage.setScene(sc);
// On close request check for the condition
popupStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Boolean readytoClose = false;
for (ToggleButton toggle : toggles) {
if (toggle.isSelected()) {
readytoClose = true;
break;
}
}
// Consume the event a show a dialog
if (!readytoClose) {
event.consume();
Alert alert = new Alert(AlertType.INFORMATION,
"At least one card has be to be selected!");
alert.showAndWait();
}
}
});
popupStage.show();
}
});
root.setCenter(b);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
private void initPopUpStage() {
popupStage = new Stage();
popupStage.initOwner(primaryStage);
popupStage.initStyle(StageStyle.UNDECORATED);
// On focus loss, close the window
popupStage.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
// Rather than popupStage.close(); fire the event manually
if (!newValue)
popupStage.fireEvent(new WindowEvent(popupStage, WindowEvent.WINDOW_CLOSE_REQUEST));
}
});
}
public static void main(String[] args) {
launch(args);
}
}
Update:
To make the main Stage unavailable I have added this line:
root.disableProperty().bind(popupStage.showingProperty());
This will disable the root BorderPane while the pop-up stage is showing. As soon as the pop-up window closed, the main window is enabled again.

close Javafx class application in java application

i have an application in java, and this have a one popup with javafx application (embed videos from Youtube). I see this correctly but when i close this popup, the javafx thread not close and javafx application running in background. This is my javafx class:
public class JavaFXClass extends Application {
#Override
public void start(final Stage stage) throws Exception {
final WebView webview = new WebView();
/*...*/
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.runLater( new Runnable() {
#Override
public void run() {
//I need stop javafx when this class close.
}
});
}
});
stage.show();
}
public static void LoadClass(String Data) { //I use this function to load class
/*...*/
launch(); //return error when i re-call this function (already launch).
}
If i put webview.getEngine().load(null); Platform.exit(); code in the "OnCloseRequest" works fine but an exception is created ("Attempt to call defer when toolkit not running")
i need use webview.getEngine().load(null); or similar because if i not use this, the video in webview remain playing in background. And if i not use Platform.exit() the main frame crashes (lock).
Sorry for my bad english, tried to write the best I could
use this:
[...]
stage.setOnCloseRequest(this.getCloseSystemEvent());
}
public EventHandler<WindowEvent> getCloseSystemEvent() {
return new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.exit();
}
};
}
Also, you should check the concurrency API. Your code prevents the runtime from closing the thread properly.

JavaFX integration with Spring rest client [duplicate]

How to call the launch() more than once in java i am given an exception as "ERROR IN MAIN:java.lang.IllegalStateException: Application launch must not be called more than once"
I have create rest cleint in my java application when request comes it call javafx and opening webview after completing webview operarion am closing javafx windows using Platform.exit() method. when second request comes am getting this error how to reslove this error.
JavaFx Application Code:
public class AppWebview extends Application {
public static Stage stage;
#Override
public void start(Stage _stage) throws Exception {
stage = _stage;
StackPane root = new StackPane();
WebView view = new WebView();
WebEngine engine = view.getEngine();
engine.load(PaymentServerRestAPI.BROWSER_URL);
root.getChildren().add(view);
engine.setJavaScriptEnabled(true);
Scene scene = new Scene(root, 800, 600);
stage.setScene(scene);
engine.setOnResized(new EventHandler<WebEvent<Rectangle2D>>() {
public void handle(WebEvent<Rectangle2D> ev) {
Rectangle2D r = ev.getData();
stage.setWidth(r.getWidth());
stage.setHeight(r.getHeight());
}
});
JSObject window = (JSObject) engine.executeScript("window");
window.setMember("app", new BrowserApp());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
RestClient Method:
Calling to JavaFX application
// method 1 to lanch javafx
javafx.application.Application.launch(AppWebview.class);
// method 2 to lanch javafx
String[] arguments = new String[] {"123"};
AppWebview .main(arguments);
You can't call launch() on a JavaFX application more than once, it's not allowed.
From the javadoc:
It must not be called more than once or an exception will be thrown.
Suggestion for showing a window periodically
Just call Application.launch() once.
Keep the JavaFX runtime running in the background using Platform.setImplicitExit(false), so that JavaFX does not shutdown automatically when you hide the last application window.
The next time you need another window, wrap the window show() call in Platform.runLater(), so that the call gets executed on the JavaFX application thread.
For a short summary implementation of this approach:
See the answer by sergioFC
If you are mixing Swing you can use a JFXPanel instead of an Application, but the usage pattern will be similar to that outlined above.
For an example of the JFXPanel apprach, see Irshad Babar
s answer.
Wumpus Sample
This example is bit more complicated than it needs to be because it also involves timer tasks. However it does provide a complete stand-alone example, which might help sometimes.
import javafx.animation.PauseTransition;
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.*;
// hunt the Wumpus....
public class Wumpus extends Application {
private static final Insets SAFETY_ZONE = new Insets(10);
private Label cowerInFear = new Label();
private Stage mainStage;
#Override
public void start(final Stage stage) {
// wumpus rulez
mainStage = stage;
mainStage.setAlwaysOnTop(true);
// the wumpus doesn't leave when the last stage is hidden.
Platform.setImplicitExit(false);
// the savage Wumpus will attack
// in the background when we least expect
// (at regular intervals ;-).
Timer timer = new Timer();
timer.schedule(new WumpusAttack(), 0, 5_000);
// every time we cower in fear
// from the last savage attack
// the wumpus will hide two seconds later.
cowerInFear.setPadding(SAFETY_ZONE);
cowerInFear.textProperty().addListener((observable, oldValue, newValue) -> {
PauseTransition pause = new PauseTransition(
Duration.seconds(2)
);
pause.setOnFinished(event -> stage.hide());
pause.play();
});
// when we just can't take it anymore,
// a simple click will quiet the Wumpus,
// but you have to be quick...
cowerInFear.setOnMouseClicked(event -> {
timer.cancel();
Platform.exit();
});
stage.setScene(new Scene(cowerInFear));
}
// it's so scary...
public class WumpusAttack extends TimerTask {
private String[] attacks = {
"hugs you",
"reads you a bedtime story",
"sings you a lullaby",
"puts you to sleep"
};
// the restaurant at the end of the universe.
private Random random = new Random(42);
#Override
public void run() {
// use runlater when we mess with the scene graph,
// so we don't cross the streams, as that would be bad.
Platform.runLater(() -> {
cowerInFear.setText("The Wumpus " + nextAttack() + "!");
mainStage.sizeToScene();
mainStage.show();
});
}
private String nextAttack() {
return attacks[random.nextInt(attacks.length)];
}
}
public static void main(String[] args) {
launch(args);
}
}
Update, Jan 2020
Java 9 added a new feature called Platform.startup(), which you can use to trigger startup of the JavaFX runtime without defining a class derived from Application and calling launch() on it. Platform.startup() has similar restrictions to the launch() method (you cannot call Platform.startup() more than once), so the elements of how it can be applied is similar to the launch() discussion and Wumpus example in this answer.
For a demonstration on how Platform.startup() can be used, see Fabian's answer to How to achieve JavaFX and non-JavaFX interaction?
I use something like this, similar to other answers.
private static volatile boolean javaFxLaunched = false;
public static void myLaunch(Class<? extends Application> applicationClass) {
if (!javaFxLaunched) { // First time
Platform.setImplicitExit(false);
new Thread(()->Application.launch(applicationClass)).start();
javaFxLaunched = true;
} else { // Next times
Platform.runLater(()->{
try {
Application application = applicationClass.newInstance();
Stage primaryStage = new Stage();
application.start(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
try this, I tried this and found successful
#Override
public void start() {
super.start();
try {
// Because we need to init the JavaFX toolkit - which usually Application.launch does
// I'm not sure if this way of launching has any effect on anything
new JFXPanel();
Platform.runLater(new Runnable() {
#Override
public void run() {
// Your class that extends Application
new ArtisanArmourerInterface().start(new Stage());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}

Categories