11 Replies Latest reply: Nov 16, 2012 7:11 PM by 971758 RSS

    Closing a window from the controller of that window

    971758
      In my main controller class I have


      public static final Stage fpStage =new Stage();
      
      
                          fpStage.setScene(scene);
                          fpStage.show();
      okay in my secondary controller class I have
      import particlesxml.MainwindowController;
      
      
      this.okayButton.setOnAction(new EventHandler<ActionEvent>() {
      
                  @Override
                  public void handle(ActionEvent event)  {
                    
                    MainwindowController.fpStage.hide();
                      
                      
                      
                      
                  }//end of handle
              }); //end of action event and set on action
              
      This compiles just fine but does not work!!!. How do we close window2 brought up by java controller for window1, from java controller for window2.

      fpStage for my project is the Stage (window) for Window2.
        • 1. Re: Closing a window from the controller of that window
          971758
          Making a static method for it in the Main controller and calling it from the secondary controller does not work either.
           public static void fpClose()
              {
                  fpStage.hide();
              }
          again it all compiles just fine. No exceptions either. It just doesn't work.
          • 2. Re: Closing a window from the controller of that window
            James_D
            This works for me.

            (I'm not advocating this style, BTW; I have no idea what the effect of ignoring the Stage passed into the main application's start(...) method might be; I also really dislike making a Stage available to another class simply by defining it as a public constant.)

            WindowCloseTest.java
            import javafx.application.Application;
            import javafx.fxml.FXMLLoader;
            import javafx.stage.Stage;
            public class WindowCloseTest extends Application {
              @Override
              public void start(Stage primaryStage) throws Exception {
                FXMLLoader.load(getClass().getResource("WindowCloseTest.fxml"));
              }
              public static void main(String[] args) {
                launch(args);
              }
            }
            WindowCloseTest.fxml
            <?xml version="1.0" encoding="UTF-8"?>
            
            <?import javafx.scene.layout.BorderPane?>
            <?import javafx.scene.shape.Rectangle?>
            
            <BorderPane xmlns:fx="http://javafx.com/fxml" fx:id="root" fx:controller="WindowCloseTestController">
                 <center>
                   <Rectangle fill="GREEN" width="200" height="200"/>
                 </center>
                 <bottom><fx:include source="WindowCloseButtons.fxml" fx:id="windowCloseButtons"/></bottom>
            </BorderPane>
            WindowCloseTestController.java
            import javafx.fxml.FXML;
            import javafx.scene.Parent;
            import javafx.scene.Scene;
            import javafx.stage.Stage;
            import javafx.stage.Window;
            
            public class WindowCloseTestController {
              
              private @FXML Parent root ;
              private @FXML WindowCloseButtonsController windowCloseButtonsController ;
              public static final Stage stage  = new Stage();
              
              public void initialize() {
                stage.setScene(new Scene(root, 400, 200));
                stage.show();
              }
            
            }
            WindowCloseButtons.fxml
            <?xml version="1.0" encoding="UTF-8"?>
            
            <?import javafx.scene.layout.HBox?>
            <?import javafx.scene.control.Button?>
            
            <HBox xmlns:fx="http://javafx.com/fxml" fx:controller="WindowCloseButtonsController">
                 <Button text="Close" onAction="#close" />
            </HBox>
            WindowCloseButtonsController.java
            public class WindowCloseButtonsController {
              public void close() {
                WindowCloseTestController.stage.hide();
              }
            }
            • 3. Re: Closing a window from the controller of that window
              971758
              Its very interesting the way you did your second window. It appears that one line brought up a new window.

              <bottom><fx:include source="WindowCloseButtons.fxml" fx:id="windowCloseButtons"/></bottom>


              I did not code fxml I let scenebuilder make it for me. Its about 460 lines of xml like code.
              Anyway I made the second window differently I did it in Javafx like so:

                  Scene scene = new Scene(fp);
                                  fpStage.setTitle("Fractal Particle");
                                  fpStage.setScene(scene);
                                  fpStage.show();
              To be perfectly honest with you I do not know a whole lot about the fxml other than it roughly corresponds to equivalent java component placement. As for editing the files directly. I try to avoid it if I can.


              I will try tomorrow to see if I can use your solution.
              • 4. Re: Closing a window from the controller of that window
                James_D
                This line
                <bottom><fx:include source="WindowCloseButtons.fxml" fx:id="windowCloseButtons"/></bottom>
                doesn't create a second window: it places the Node defined in WindowCloseButtons.fxml into the bottom of the enclosing BorderPane. In other words, <fx:include source="filename" /> just evaluates to a Node in the same way that a <SomeClass /> tag does (where SomeClass is a subclass of Node). However, if that were placed in a second window, the close button it defines would close the window defined in the WindowTestController class. Again, there are (much) better OO designs than this which would properly encapsulate your classes and avoid excessive coupling between them, but I just wanted to show you your technique should work.

                I actually created the window in the same way you did; it's in the WindowTestController class defined in that post. If you copy and save each of those files, it's a complete executable example.

                I recommend getting somewhat acquainted with FXML; it's not too complex. The tutorial at Oracle http://docs.oracle.com/javafx/2/fxml_get_started/jfxpub-fxml_get_started.htm is a good start, and the reference http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html is fairly short and easy to read.
                • 5. Re: Closing a window from the controller of that window
                  James_D
                  Also, maybe I am interpreting this as being more complex than it really is.

                  If the controller is a controller for nodes that are displayed in the window you want to close, it's pretty trivial:

                  Example.fxml
                  <?xml version="1.0" encoding="UTF-8"?>
                  
                  <?import javafx.scene.layout.HBox?>
                  <?import javafx.scene.control.Button ?>
                  <HBox xmlns:fx="http://javafx.com/fxml" fx:id="root" fx:controller="ExampleController">
                    <Button text="Close" onAction="#close"/>
                  </HBox>
                  ExampleController.java
                  import javafx.fxml.FXML ;
                  import javafx.scene.Node ;
                  public class ExampleController {
                    private @FXML Node root ;
                    public void close() {
                        root.getScene().getWindow().hide();
                    }
                  }
                  Example.java
                  import javafx.application.Application ;
                  import javafx.stage.Stage ;
                  import javafx.scene.Parent ;
                  import javafx.scene.Scene ;
                  import javafx.fxml.FXMLLoader ;
                  
                  public class Example extends Application {
                    @Override
                    public void start(Stage primaryStage) throws Exception {
                      Parent root = FXMLLoader.load(getClass().getResource("Example.fxml"));
                      Scene scene = new Scene(root, 400, 200);
                      primaryStage.setScene(scene);
                      primaryStage.show();
                    }
                    public static void main(String[] args) { launch(args); }
                  }
                  If the controller has no access to nodes that are contained in the window you're closing, then you have to do a bit more work. Of course, you should also ask yourself if that's a good design (from both a UI design point of view and an OO design point of view).
                  • 6. Re: Closing a window from the controller of that window
                    971758
                    okay I so have this code in my Controller
                     this.okayButton.setOnAction(new EventHandler<ActionEvent>() {
                    
                                @Override
                                public void handle(ActionEvent event)  {
                                  
                                  close();
                                    
                                    
                                }//end of handle
                            }); //end of action event and set on action
                    
                    
                      public void close()
                        {
                            this.root.getScene().getWindow().hide();
                        }
                    And this code in my fxml file
                    <AnchorPane id="AnchorPane" fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="481.0" prefWidth="814.0000999999975" xmlns:fx="http://javafx.com/fxml">
                    
                    
                    <Button fx:id="okayButton" graphicTextGap="4.0" mnemonicParsing="false" prefHeight="55.0" prefWidth="73.0" text="Okay" onAction="#close" >
                    But now when I run it does not bring up the second window at all. =(

                    Edited by: Alexander B. Java on Nov 9, 2012 7:37 AM
                    • 7. Re: Closing a window from the controller of that window
                      James_D
                      First, you're setting the onAction property of the okayButton twice; once in the java code (this.okayButton.setOnAction(...)) and once in the fxml (<Button fx:id="okayButton" ... onAction="#close"/>). You only need one of those.

                      What's the scenario here? I'm not sure I fully understand it. Is the okayButton supposed to close the window in which it's displayed, or is it supposed to close some other window?
                      • 8. Re: Closing a window from the controller of that window
                        971758
                        Its suppose to close the window in which it is displayed.
                        • 9. Re: Closing a window from the controller of that window
                          971758
                          okay, if the code for closing is in the fxml code for me it will not open window 2 from window 1.

                          If the code(shown previously) is only in the controller for window 2. Window 2 opens from window 1 but cannot close via okay button.

                          I hope that makes things a little clearer.
                          • 10. Re: Closing a window from the controller of that window
                            James_D
                            This sounds pretty confused. Code that opens a window looks like
                            Stage stage = ... ;
                            ...
                            stage.show();
                            Code that causes a window to close looks like
                            Stage stage = ... ; // get the reference to the stage you want to close
                            stage.close();
                            You can get the reference to the stage in which a control is displayed with
                            Window stage = someControl.getScene().getWindow();
                            I suggest you try to create something as simple as possible which has the characteristics you need; a main window containing a button, which when pressed causes a second window to open. The second window should contain a button which, when pressed, causes the same window to close. Once you have that working, you can see if your larger application matches a structure that works. (It's also easier to give assistance if you're working with something small enough that you can post a fully executable example.)
                            • 11. Re: Closing a window from the controller of that window
                              971758
                              Okay I fixed my problem. I had to write a window manager class with static variables and that was what worked. here is the code.

                              /*
                               * To change this template, choose Tools | Templates
                               * and open the template in the editor.
                               */
                              package multiwindwowtest;
                              import javafx.fxml.FXMLLoader;
                              import javafx.scene.Parent;
                              import javafx.scene.Scene;
                              import javafx.stage.Stage;
                              /**
                               *
                               * @author Workspace
                               */
                              
                              public class WindowManager {
                              
                                  public static Stage stage1 = new Stage();
                                  public static Stage stage2 = new Stage();
                              
                                  
                                  public WindowManager() 
                                  {        
                                      
                               
                                  }
                                  
                                  public void raiseWindow(int type) throws Exception
                                  {
                                  if(type==1)
                                      {
                                          Parent root = FXMLLoader.load(getClass().getResource("secondwindow.fxml"));
                                      
                                      Scene scene = new Scene(root);
                                      
                                      stage1.setScene(scene);
                                      stage1.show();    
                                          
                                      }   
                                      else
                                      {     
                                            Parent root = FXMLLoader.load(getClass().getResource("thirdwindow.fxml"));
                                      
                                      Scene scene = new Scene(root);
                                      
                                      stage2.setScene(scene);
                                      stage2.show();    
                                          
                                      }
                                  
                                  
                                  }
                                  public void closeWindow(int type)
                                  {        
                                       if(type==1)
                                      {
                                  
                                          stage1.close();
                                      }
                                       else
                                       {
                                           stage2.close();
                                       }
                                  }
                                  
                              }