When i click on the button, a FileChooser is opened. However, i can for example close the Original Stage while the FileChooser is still opened, or i still can click and switch the actual window. Check the code below
My questions are : 1- How can i make the FileChooser Closes when i close the main window ? 2- How can i make the main window not clickable when the FileChooser is opened ?
package application;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
public class Main extends Application {
#Override public void start(Stage stage) {
stage.setTitle("Main Stage");
stage.setWidth(500);
stage.setHeight(500);
stage.show();
Button button = new Button();
AnchorPane ap = new AnchorPane();
Scene scene = new Scene(ap);
ap.getChildren().addAll(button);
stage.setScene(scene);
button.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
FileChooser fileChooser = new FileChooser();
Stage stage2=new Stage();
stage2.initOwner(stage);
stage2.initModality(Modality.WINDOW_MODAL);
fileChooser.showOpenDialog(stage2);
}
});
}
public static void main(String[] args) {
launch(args);
}
}
According to the JavaDocs
If the owner window for the file dialog is set, input to all windows
in the dialog's owner chain is blocked while the file dialog is being
shown.
However, you are setting the owner window to a window that is not on the screen, so I think there is no "owner chain" in that case, and the file chooser is effectively not modal.
Why not just do
button.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
FileChooser fileChooser = new FileChooser();
fileChooser.showOpenDialog(stage);
}
});
so that you make the owner window of the file chooser the actual window?
Related
I believe I've found a bug with BorderPane. The stage will close as expected if you do not rotate the phone. However, if you rotate the phone and then click on Close the screen does nothing until you rotate the phone back to the original position and then is displays the primaryStage. The code to recreate it is very simple.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.Modality;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
final Stage stage = new Stage();
Button closeBtn = new Button("Close");
closeBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
stage.close();
}
});
FlowPane pane = new FlowPane();
pane.getChildren().addAll(new Label("Hello World!"), closeBtn);
Scene scene = new Scene(pane);
stage.initModality(Modality.APPLICATION_MODAL);
stage.initOwner(primaryStage);
stage.setScene(scene);
stage.show();
}
});
BorderPane borderPane = new BorderPane();
borderPane.setPrefHeight(Screen.getPrimary().getVisualBounds().getMaxY());
borderPane.setPrefWidth(Screen.getPrimary().getVisualBounds().getMaxX());
borderPane.setCenter(btn);
primaryStage.setScene(new Scene(borderPane));
primaryStage.show();
}
Does anyone know how to work around this issue?
build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.0.8'
}
}
apply plugin: 'org.javafxports.jfxmobile'
mainClassName = 'helloworld.HelloWorld'
version = '8u40'
repositories {
mavenLocal()
mavenCentral()
jcenter()
}
jfxmobile {
ios {
forceLinkClasses = ['ensemble.**.*']
}
android {
applicationPackage = 'org.javafxports.ensemble'
}
}
Thank you for the hints. I removed the extra stage and scene. My workaround is this.
package helloworld;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
final Group group = new Group();
final BorderPane borderPane = new BorderPane();
borderPane.setPrefHeight(Screen.getPrimary().getVisualBounds().getMaxY());
borderPane.setPrefWidth(Screen.getPrimary().getVisualBounds().getMaxX());
final Button btn = new Button("Say 'Hello World'");
borderPane.setCenter(btn);
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Button closeBtn = new Button("Close");
closeBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
group.getChildren().setAll(borderPane);
}
});
FlowPane pane = new FlowPane();
pane.getChildren().addAll(new Label("Hello World!"), closeBtn);
group.getChildren().setAll(pane);
}
});
group.getChildren().add(borderPane);
primaryStage.setScene(new Scene(group));
primaryStage.show();
}
}
While I can reproduce your issue, and you can report it here, on mobile things are a little bit different from desktop, and you shouldn't create a different stage or a different scene: just switch the nodes on the scene instead.
If you create the project with Gluon's plugin, you'll notice it uses View nodes, and you can easily switch between them, but always related to the same root (GlassPane) on the same scene.
If you need dialogs, you can use JavaFX built-in Dialogs, but Gluon already has its own dialogs, more adapted to a mobile environment.
I have a context menu, which contains a CustomMenuItem with some controls. When clicking a button, a dialog shows and the context menu hides automatically. Here is the problem: I would like to prevent the closing of the context menu when the dialog shows. How can I solve this problem?
I already have tracked done the event. When the dialog opens, a FocusUngrabEvent.FOCUS_UNGRAB event is fired, which is handled in PopupWindow. I already tried to add an EventFilter and EventHandler to the context menu for FocusUngrabEvent.FOCUS_UNGRAB and consume the event, but that does not help.
Here an SSCCE demonstrating this problem:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class PimaryStage extends Application {
#Override
public void start(Stage primaryStage) {
// The button which shows the dialog.
Button button = new Button("Some Button");
button.setOnAction((event)-> {
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Warning");
alert.setHeaderText(null);
alert.setContentText("Some Text");
alert.show();
});
// Custom menu item which contains the button.
CustomMenuItem menuItem = new CustomMenuItem(button);
menuItem.setHideOnClick(false);
// Context menu.
ContextMenu menu = new ContextMenu();
menu.getItems().add(menuItem);
// Label.
Label label = new Label("Click here to open the context menu.");
label.setContextMenu(menu);
// Set the scene and show the stage.
Scene scene = new Scene(label, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This worked for me:
#FXML
public void autoShow() {
contextmenu.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
e.consume();
}
});
}
Place the above method in your controller class and then call it from the initialize method in your controller class:
#Override
public void initialize(URL location, ResourceBundle resources) {
autoShow();
}
I have a Pane with some controls and a button. When I click on the button, I want show ProgressIndicator in center of pane without removing any controls.
When I am adding a ProgressIndicator to pane during onAction of button, it adds it below the button. I want it to overlay on the pane.
The picture below explains what I want.
Code
package fx;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage arg0) throws Exception {
final VBox bx = new VBox();
bx.setAlignment(Pos.CENTER);
TextField userName = new TextField("User Name");
userName.setMaxWidth(200);
TextField email = new TextField("Email");
email.setMaxWidth(200);
Button submit = new Button("Submit");
submit.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
ProgressIndicator pi = new ProgressIndicator();
//adding here but it is adding at below of button
//how to do here
bx.getChildren().add(pi);
//Further process
}
});
bx.getChildren().addAll(userName, email, submit);
Scene c = new Scene(bx);
arg0.setScene(c);
arg0.setMinWidth(500);
arg0.setMinHeight(500);
arg0.show();
}
public static void main(String[] args) {
Main h = new Main();
h.launch(args);
}
}
You need to use a StackPane as your root layout instead of using a VBox. StackPane allows you to stack nodes on top of each other (z-order).
On the button's action you can create a new ProgressIndicator and add it to your StackPane. I have introduced another VBox as the parent to the indicator, because I did not want the indicator to capture all the available space. You can disable the already present VBox to get the greying effect on button's action after the process is done you can enable the VBox again.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage arg0) throws Exception {
StackPane root = new StackPane();
VBox bx = new VBox();
bx.setAlignment(Pos.CENTER);
TextField userName = new TextField("User Name");
userName.setMaxWidth(200);
TextField email = new TextField("Email");
email.setMaxWidth(200);
Button submit = new Button("Submit");
submit.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
ProgressIndicator pi = new ProgressIndicator();
VBox box = new VBox(pi);
box.setAlignment(Pos.CENTER);
// Grey Background
bx.setDisable(true);
root.getChildren().add(box);
}
});
bx.getChildren().addAll(userName, email, submit);
root.getChildren().add(bx);
Scene c = new Scene(root);
arg0.setScene(c);
arg0.setMinWidth(500);
arg0.setMinHeight(500);
arg0.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have an internal jfxtra window. On clicking a button, I want to bring it forward.
The code that I have tried :
window w = new window("mdi win");
private Stage primaryStage;
private BorderPane rootLayout;
...
public void win() {
Parent bla = FXMLLoader.load(getClass().getResource("bla.fxml"));
w.getContentPane().getChildren().add(bla);
rootLayout.getChildren().add(w);
}
private void wfront(ActionEvent event) throws Exception {
w.isMoveToFront(); // is not?
}
How to make it possible?
So you made me curious and I went through the JFXtras docs. I came to know that Window in Jfxtras extends Control. So there is a method called toFront which can be fired on it. To show this I have created a sample for you.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import jfxtras.scene.control.window.Window;
public class NewWindow extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane stackPane = new StackPane();
Button button = new Button("Click Me to show Window !");
Window window = new Window("Cick Me to bring me to front");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
window.toFront();
window.setTitle("I am on the Front");
}
});
window.setPrefSize(200, 200);
stackPane.getChildren().addAll(window, button);
Scene scene = new Scene(stackPane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Let me know, if you are looking for something else !
I have 2 screens in application. First screen(MainController class) which opens with running application from Eclipse.
And second screen(SecondController class) which opens on button located in first screen.
How can I make some kind of 'Back' button in second screen which will show back first screen?
I'm creating the visual part of the application in JavaFX Scene Builder if it matters.
Here is a small example, containing to screens, to show how you can achieve what you are looking for
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class TwoScreensWithInterchange extends Application {
#Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(loadScreenOne(), 200, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
public VBox loadScreenOne()
{
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
final Button button = new Button("Switch Screen");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
button.getScene().setRoot(loadScreenTwo());
}
});
Text text = new Text("Screen One");
vBox.getChildren().addAll(text, button);
vBox.setStyle("-fx-background-color: #8fbc8f;");
return vBox;
}
public VBox loadScreenTwo()
{
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
final Button button = new Button("Back");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
button.getScene().setRoot(loadScreenOne());
}
});
Text text = new Text("Screen Two");
vBox.getChildren().addAll(text, button);
return vBox;
}
}