I'm creating a new modal dialog from the main controller class. How do I set some textfield values in the dialog before it is displayed?
URL url = getClass().getResource("SeedNodeForm.fxml");
Stage stage = new Stage();
stage.setTitle("Seed Node Information");
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(((Node) event.getSource()).getScene().getWindow());
stage.initStyle(StageStyle.UTILITY);
Parent root = FXMLLoader.load(url);
stage.setScene(new Scene(root));
stage.centerOnScreen();
textfield1.setValue("foo!");
textfield2.setValue("foo2");
stage.showAndWait();
Thank you Uluk Biy - your link led me to the answer which is:
// get the controller from the loader
SeedNodeFormController c = (SeedNodeFormController) fxmlLoader.getController();
// call setter in controller routine to set needed values
c.setSeedNode(value);
Related
Hello I am having an JavaFX app with few controllers and I have 2 options to get back to previous screen. User can click button 'leave' or after finishing some tasks on this screen will be moved to previous automatically. I have problem here because I've created method wiut fxml annotation which takes ActionEvent object as parameter and is called when user click button and when user will finish tasks and should be moved automatically to previous screen I cannot call this method because I dont this object, it's created when an action - click in this case is made. How can I make it possible for both 'exit' options?
So here is my method which is used 'onAction' for my button:
#FXML
private void leaveRoomAction(ActionEvent event) {
try {
removePlayerFromRoom();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("LobbyView.fxml"));
Parent root = (Parent) loader.load();
LobbyController lobbyController = (LobbyController)loader.getController();
lobbyController.setClientThread(client);
lobbyController.setNameAndBalance(client.getPlayer().getName());
Scene scene = new Scene(root);
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
And later in other part of programe:
if(isFinished()){
//here I want write leaving this screen and getting back to previous
}
First, find another way to get a reference to the Stage. Since you almost certainly have a reference to some node in the scene in your controller, you can replace
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
with
Stage stage = (Stage) anyNode.getScene().getWindow();
where anyNode is just something you have injected into the controller.
Now you don't need the parameter at all, so you can just remove it. I.e. you end up with
#FXML
private Node anyNode ; // probably a more specific type than Node.
#FXML
private void leaveRoomAction() {
try {
removePlayerFromRoom();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("LobbyView.fxml"));
Parent root = (Parent) loader.load();
LobbyController lobbyController = (LobbyController)loader.getController();
lobbyController.setClientThread(client);
lobbyController.setNameAndBalance(client.getPlayer().getName());
Scene scene = new Scene(root);
Stage stage = anyNode.getScene().getWindow();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
And now you can just call the method:
if ( isFinished() ) {
leaveRoomAction()
}
I have Controller.java for Scene.fxml and ControllerSettings.java for WindowSettings.fxml. In Controller.java I create a new popup window (no dialog) with following method:
#FXML
public void handleSubmenuSettings(ActionEvent event) throws IOException {
Stage stage;
Parent root;
ControllerSettings controller;
stage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("WindowSettings.fxml"));
root = (Parent) loader.load();
controller = (ControllerSettings) loader.getController();
stage.setScene(new Scene(root));
stage.setTitle("Settings");
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.initOwner(submenuSettings.getScene().getWindow());
stage.showAndWait();
stage.setOnCloseRequest(e -> {
e.consume();
controller.saveSettings();
stage.close();
});
}
I want to save the settings when closing the new popup window but that doesn't work with stage.setOnCloseRequest.
The showAndWait() method will block execution until the window has closed; i.e. subsequent statements will not be executed until after the window is closed. So you don't register the listener for the close request until after the window has been closed. Clearly, no request to close the window will occur after the window is closed, so your handler is never invoked.
It's not really clear why you are using a close request handler anyway. Presumably you simply want to call controller.saveSettings() after the window closes. Since you are using showAndWait() you can just do:
#FXML
public void handleSubmenuSettings(ActionEvent event) throws IOException {
Stage stage;
Parent root;
ControllerSettings controller;
stage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("WindowSettings.fxml"));
root = (Parent) loader.load();
controller = (ControllerSettings) loader.getController();
stage.setScene(new Scene(root));
stage.setTitle("Settings");
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.initOwner(submenuSettings.getScene().getWindow());
stage.showAndWait();
controller.saveSettings();
}
So here is the problem I am having: I have 3 button, when I press one of the 3 buttons the new scene will display. Yet I cant seem to figure out how to make different panes appear visible depending on which button is pressed. what is the best method to perform this action? How do i use Id's from different scene controllers in order to change the properties of the pane within the main scene button listener?
currently on my main controller when each button is released the below action listener executes and displays secondscreen.fxml. the secondscreen.fxml has 2 different panes, depending on which button is pressed I need 1 of the 2 pains to set to visable.
#FXML
public void handleButtonAction(MouseEvent event) {
Parent root;
try {
root = FXMLLoader.load(getClass().getResource("secondscreen.fxml"));
Stage stage = new Stage();
stage.setTitle("title");
stage.setScene(new Scene(root));
stage.show();
((Node)(event.getSource())).getScene().getWindow();
} catch (Exception e) {
e.printStackTrace();
}
}
After you load a view, you can access its controler.
Keep in mind, that your controller must be asigned to your fxml file fx:controller="your.package.SecondScreenController.java"
FXMLLoader loader = new FXMLLoader.load(getClass().getResource("secondscreen.fxml"));
// load view
Parent root = loader.load();
// after view is loaded, access its controller
SecondScreenController controller = (SecondScreenController) loader.getController();
// modify view using methods on your controller
controller.setTabIndex(0)
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
Ater some googling, I figured that I can change scenes while remaining in the same stage by assigning this method to a button:
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
I don't understand the second line though. What does the stage and node in parenthesis mean? Is it some type of casting? Does it refer to the "primary" stage somehow? I'll be very thankful if someone could fully explain this line or tell me what material I've missed.
The syntax in which the type is placed in parentheses ahead of the expression is a downcast, which is explained nicely here and here. If you expand the code, it might be clearer:
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
// get the source of the event
Object eventSource = event.getSource();
// the event only knows its source is some kind of object, however, we
// registered this listener with a button, which is a Node, so we know
// the actual runtime type of the source must be Button (which is a Node)
// So tell the compiler we are confident we can treat this as a Node:
Node sourceAsNode = (Node) eventSource ;
// get the scene containing the Node (i.e. containing the button):
Scene oldScene = sourceAsNode.getScene();
// get the window containing the scene:
Window window = oldScene.getWindow();
// Again, the Scene only knows it is in a Window, but we know we specifically
// put it in a stage. So we can downcast the Window to a Stage:
Stage stage = (Stage) window ;
// Equivalently, just omitting all the intermediate variables:
// Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
IMHO this is pretty badly written code. Firstly, downcasting to some extent sidesteps the usual compile-time type checks, relying on our own analysis of our coding logic to avoid runtime exceptions. Thus it is good practice to avoid it when possible.
In this case, you state that this code is part of a handler registered with a button. Therefore, the source of the event is the button. So, instead of going through all those steps to get back a reference to the button, we can just use an existing reference. In other words, you have something like:
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
});
Here ((Node) event.getSource()) must be the button, so you can immediately simplify to
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage = (Stage) button.getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
});
Secondly, there's really no need to replace the Scene at all: why not just replace the root of the existing Scene? For this you can do
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Scene scene = button.getScene();
scene.setRoot(root);
});
(clearly the Stage is already showing, since the user clicked on the button, so stage.show() is redundant).
If you prefer, you can simplify that to
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
button.getScene().setRoot(root);
});
or even just
button.setOnAction(event ->
button.getScene().setRoot(FXMLLoader.load(getClass().getResource("view/bambam"))));
I can't figure out how to create a modal window in JavaFX. Basically I have file chooser and I want to ask the user a question when they select a file. I need this information in order to parse the file, so the execution needs to wait for the answer.
I've seen this question but I've not been able to find out how to implement this behavior.
In my opinion this is not good solution, because parent window is all time active.
For example if You want open window as modal after click button...
private void clickShow(ActionEvent event) {
Stage stage = new Stage();
Parent root = FXMLLoader.load(
YourClassController.class.getResource("YourClass.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();
}
Now Your new window is REALY modal - parent is block.
also You can use
Modality.APPLICATION_MODAL
Here is link to a solution I created earlier for modal dialogs in JavaFX 2.1
The solution creates a modal stage on top of the current stage and takes action on the dialog results via event handlers for the dialog controls.
JavaFX 8+
The prior linked solution uses a dated event handler approach to take action after a dialog was dismissed. That approach was valid for pre-JavaFX 2.2 implementations. For JavaFX 8+ there is no need for event handers, instead, use the new Stage showAndWait() method. For example:
Stage dialog = new Stage();
// populate dialog with controls.
...
dialog.initOwner(parentStage);
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.showAndWait();
// process result of dialog operation.
...
Note that, in order for things to work as expected, it is important to initialize the owner of the Stage and to initialize the modality of the Stage to either WINDOW_MODAL or APPLICATION_MODAL.
There are some high quality standard UI dialogs in JavaFX 8 and ControlsFX, if they fit your requirements, I advise using those rather than developing your own. Those in-built JavaFX Dialog and Alert classes also have initOwner and initModality and showAndWait methods, so that you can set the modality for them as you wish (note that, by default, the in-built dialogs are application modal).
You can create application like my sample. This is only single file JavaFX application.
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Stage stage;
stage = new Stage();
final SwingNode swingNode = new SwingNode();
createSwingContent(swingNode);
StackPane pane = new StackPane();
pane.getChildren().add(swingNode);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Swing in JavaFX");
stage.setScene(new Scene(pane, 250, 150));
stage.show();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private void createSwingContent(final SwingNode swingNode) {
SwingUtilities.invokeLater(() -> {
try {
Path currentRelativePath = Paths.get("");
String s = currentRelativePath.toAbsolutePath().toString();
JasperDesign jasperDesign = JRXmlLoader.load(s + "/src/reports/report1.jrxml");
String query = "SELECT * FROM `accounttype`";
JRDesignQuery jrquery = new JRDesignQuery();
jrquery.setText(query);
jasperDesign.setQuery(jrquery);
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
JasperPrint JasperPrint = JasperFillManager.fillReport(jasperReport, null, c);
//JRViewer viewer = new JRViewer(JasperPrint);
swingNode.setContent(new JRViewer(JasperPrint));
} catch (JRException ex) {
Logger.getLogger(AccountTypeController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}