I show here an image of my welcome scene.
The current behavior of the Create New Project button is shown here:
Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
stage.hide();
Parent root = FXMLLoader.load(getClass().getResource("/view/scene/configure/NewProjectConfigureScene.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Configure New Project Settings");
stage.setScene(scene);
stage.show();
To explain it in words: the button is pressed -> I get the stage -> hide the current scene -> switch the stage to have a new scene -> re-display the stage. This behavior is working.
I am new to GUI programming so please bear with me as I explain what I need.
I am now trying to add a small feature where when the Create New Project button is pressed, a loading message appears in the current scene, I force the GUI to wait for a few seconds (so that the user has time to see this "loading" message) before continuing onto the next scene. The loading message would look something like this.
I really want to implement this feature because a loading message followed by a wait could be more intuitive and consequently improve my users experience when using the program.
My initial attempt was to do the following:
statusText.setText("Please wait..."); // statusText is the "loading message"
Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
try {
Thread.sleep(2000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
stage.hide();
Parent root = FXMLLoader.load(getClass().getResource("/view/scene/configure/NewProjectConfigureScene.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Configure New Project Settings");
stage.setScene(scene);
stage.show();
I just read here that you can never sleep the UI thread because it will freeze the entire application. So I've been trying the approach mentioned in the first answer from the above link, which says to use javafx.concurrent.Task, however I have been trying for a long time to no avail.
How do I update the UI, forcibly wait for a few seconds, and then display a new scene?
Instead of sleeping the thread, use a PauseTransition and load your new scene after the pause has finished.
createNewProject.setOnAction(event -> {
statusText.setText("Please wait...");
PauseTransition pause = new PauseTransition(
Duration.seconds(1),
);
pause.setOnFinished(event -> {
Parent root = FXMLLoader.load(
getClass().getResource(
"/view/scene/configure/NewProjectConfigureScene.fxml"
)
);
Scene scene = new Scene(root);
stage.setTitle("Configure New Project Settings");
stage.setScene(scene);
stage.sizeToScene();
});
pause.play();
});
The above code assumes you have just a single stage, so you resize your "Welcome" stage to become the "Configure New Project Settings" stage.
You should try adding in ControlsFX this will help.
You can do the following:
Service<T> service = new Service<T>(){
#Override
protected Task<T> createTask() {
return new Task<T>() {
#Override
protected T call() throws Exception {
//Do your processing here. }
};
}
};
service.setOnSucceeded(event -> {//do your processing});
service.setOnFailed(event -> {//do your processing});
ProgressDialog pd = new ProgressDialog(service);
pd.setContentText("Please wait while the window loads...");
pd.initModality(Modality.WINDOW_MODAL);
pd.initOwner(stage);
service.start();
This will put your code on the background thread. ControlsFX dialogs start and stop with the service.
Related
There is a button in a scene of the main window. When it's clicked, the new window is created, according following code:
public static void create()
{
Stage stage = new Stage();
AnchorPane pane = new AnchorPane();
//Here i add some into pane
stage.setScene(new Scene(pane));
stage.setWidth(500);
stage.setHeight(600);
stage.show();
}
I'd like the main window will remain blocked (i.e. an user won't be able to click on buttons, type text, resize or interact with it with other ways) until the additional window is closed.
Here is a link that shows exactly what you're looking for: http://www.javafxtutorials.com/tutorials/creating-a-pop-up-window-in-javafx/
Here is the main part of the code you need to add:
stage.initModality(Modality.APPLICATION_MODAL);
stage.initOwner(btn1.getScene().getWindow());
stage.showAndWait(); // This forces the program to pay attention ONLY to this popup window until its closed
Hope this helps.
I'm having a JavaFX-GUI that enables the user to scan.
This process is taking a while. So the user should neither keep clicking around, nor should anyone think the program hung itself.
My solution was a modal window that is just in front of the whole GUI and and disappears itself when everything is finished.
The interface consists of a FXML-Controller, the FXML-File and the MainApp.
So far I'm calling it in the Controller:
Stage stage = Messages.beforeScan(event);
s.scan(filename);
stage.close();
The beforeScan-Method looks like that (Taken from How to create a modal window in JavaFX 2.1 ):
public static Stage beforeScan(Event event) {
Stage stage = new Stage();
try {
Parent root = FXMLLoader.load(
FXMLController.class.getResource("/fxml/Scene.fxml"));
stage.setScene(new Scene(root));
stage.setTitle("My modal window");
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(((Node)event.getSource()).getScene().getWindow());
stage.show();
} catch (IOException ex) {
Logger.getLogger(Meldungen.class.getName()).log(Level.SEVERE, null, ex);
}
return stage;
}
Yet this is not successful. If I comment out stage.close(); I can still use my main GUI.
So a different approach:
Instead of importing the Scene from the controller I tired to obtain it from the MainApp-Class:
public static Stage beforeScan(Event event) {
Stage stage = new Stage();
stage.setScene(MainApp.getStage.getScene());
stage.setTitle("My modal window");
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(((Node) event.getSource()).getScene().getWindow());
stage.show();
return stage;
}
But this just crashes everything with a StackOverflow.
The Popup (Taken from the example here ) is not helpful either. It is even only opened after the scan.
Using an Alert seemed like a good idea, but doing it that way is not only locking the screen but the program itself:
public Alert beforeScan(Event event) {
javafx.scene.control.Alert alert = new Alert(Alert.AlertType.NONE, "Scan in progress");
alert.showAndWait();
return alert;
}
How should a screen-locking modal window/popup be done properly?
I'm having difficulty finding out if this is even possible. The common behavior that most people want is to fade out an extension of a node, which is entirely possible through a FadeTransition
However, I'm trying to fade out an entire stage, so imagine closing the running program and instead of simply killing the windows (i.e. showing -> not showing), I would like the window (stage) to fade out over 2 seconds like a toast or notification would.
Create a timeline with a KeyFrame that changes the opacity of the stage's scene's root node. Also make sure to set the Stage style and the scene fill to transparent. Then make the program exit once the timeline is finished.
Below is an application with a single big button that, when clicked, will take 2 seconds to fade away, and then the program will close.
public class StageFadeExample extends Application {
#Override
public void start(Stage arg0) throws Exception {
Stage stage = new Stage();
stage.initStyle(StageStyle.TRANSPARENT); //Removes window decorations
Button close = new Button("Fade away");
close.setOnAction((actionEvent) -> {
Timeline timeline = new Timeline();
KeyFrame key = new KeyFrame(Duration.millis(2000),
new KeyValue (stage.getScene().getRoot().opacityProperty(), 0));
timeline.getKeyFrames().add(key);
timeline.setOnFinished((ae) -> System.exit(1));
timeline.play();
});
Scene scene = new Scene(close, 300, 300);
scene.setFill(Color.TRANSPARENT); //Makes scene background transparent
stage.setScene(scene);
stage.show();
}
public static void main (String[] args) {
launch();
}
}
I'm working on this simple application and trying to create a new stage/window when clicking on a button. I get this work when using a simple fxml-document with only one AnchorPane. In the scene I want to pop-up, there is a TabPane with two tabs. I've imported one fxml-document into each tab, and when I do that a new AnchorPane is created in each tab. So when I click the button in main scene nothing is happening. I really don't know how to solve this, does anybody have any ideas?
This is the code I'm using right now to show a new stage.
#FXML
private void showAddStage(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Add.fxml"));
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
} catch (IOException e) {}
}
I have an external monitor plugged into my laptop. I want to display a new Stage on this external screen in fullscreen, undecorated and modal mode. I know how to achieve all of this in pure Java/Swing combination, but I'm stucked with JavaFX implementation of such functionality.
I know, there is a Screen API, which I can use e.g to get screen list, say:
List<Screen> allScreens = Screen.getScreens();
...but I don't know where I could go from here.
UPDATE : 2014/08/03, 22:21
I've found the way to solve my problem, so I've decided to share my approach to it. So far I haven't found a better solution.
Button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent ae) {
List<Screen> allScreens = Screen.getScreens();
if (allScreens.size() > 1) {
Screen secondaryScreen = allScreens.get(1);
Rectangle2D bounds = secondaryScreen.getVisualBounds();
Stage stage = new Stage();
stage.setX(bounds.getMinX());
stage.setY(bounds.getMinY());
stage.setWidth(bounds.getWidth());
stage.setHeight(bounds.getHeight());
stage.initStyle(StageStyle.UNDECORATED);
stage.initModality(Modality.APPLICATION_MODAL);
stage.show();
} else {
Stage stage = new Stage();
stage.setFullScreen(true);
stage.initStyle(StageStyle.UNDECORATED);
stage.initModality(Modality.APPLICATION_MODAL);
stage.show();
}
}
});