-1

I am new to Java FX and I am having a problem trying to get the Title of the stage, as I wish to parse it and use in the SQL Create that will be used later in this application that I am developing... the problem is I get a NullPointerException with the controller initialise for this code...

this_stage = (Stage) create_post.getScene().getWindow();
post_type=this_stage.getTitle();
System.out.println("this_stage_title:"+post_type );

Yet when I embed this in the setOnAction for the button, it does work... can some-one suggest how I can get this to work, as I need it to get the post_type from the title onLoad [ie as the Window initialises], and then parse it [for the typing of posting which will either be "EVENT, SALE, POST" this is background information to this particular problem]... anyway, here is my code..

CALLING MAIN PROGRAM:

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;

public class test_main extends Application
{
    public void start(Stage primaryStage) throws Exception 
    {
        try 
            {
                Parent post_create = FXMLLoader.load(  getClass().getResource("create.fxml"));
                // Note: the path is not relative to the package that this file is in
                // but the CLASSPATH from the src/
                Stage post_create_stage = new Stage();
                post_create_stage.setTitle("Create Event Posting");
                post_create_stage.setScene(new Scene(post_create));  
                post_create_stage.show();

            }// close try
            catch (Exception e)
            {
                e.printStackTrace();

            }// close catch (Exception e)
    }// close public void start(Stage primaryStage) throws Exception 

    public static void main(String[] args) 
    {
        //launch the Login UI
        launch(args);
        }


    }// close 

MY FXML FILE

    <?xml version="1.0" encoding="UTF-8"?>

    <?import javafx.scene.control.Button?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.layout.AnchorPane?>
    <?import javafx.scene.layout.VBox?>

    <AnchorPane 
    fx:id="create_post" 
    prefHeight="400.0" 
    prefWidth="800.0"
    xmlns="http://javafx.com/javafx/11.0.1" 
    xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="createController" >
       <children>
          <VBox prefHeight="138.0" prefWidth="100.0">
             <children>
                <Label fx:id="lbl_stage_title" text="get stage name" />
                <Button fx:id="btn_create_details_save" mnemonicParsing="false" text="Save" />
             </children>
          </VBox>
       </children>
    </AnchorPane>

MY CONTROL CLASS

    ////////////////////////////////////////////////////////////////////////////////
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.layout.AnchorPane;
    import model.connectionTest;
    import javafx.scene.control.Alert;
    import javafx.scene.control.Alert.AlertType;
    import javafx.scene.control.Button;
    import javafx.scene.control.ButtonType;
    import javafx.scene.control.Label;
    import javafx.scene.control.TextField;
    //import javafx.collections.FXCollections;
    //import javafx.collections.ObservableList;
    import javafx.stage.Stage;
    import javafx.stage.Window;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.event.Event;

    //Import the classes for database query
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    //import model.table_setup_view_postings;

    //import javafx.collections.FXCollections;
    //import javafx.collections.ObservableList;
    import javafx.fxml.Initializable;
    //import javafx.scene.control.ListCell;
    //import javafx.scene.control.ListView;
    //import javafx.util.Callback;

    //import resources for the table view
    //import javafx.scene.control.TableColumn;
    //import javafx.scene.control.TableView;
    //import javafx.scene.control.cell.PropertyValueFactory;
    //import model.Item;

    import java.net.URL;
    import java.util.Optional;
    import java.util.ResourceBundle;

    //import model.posting;

    public class createController implements Initializable
    {
    ////////////////////////////////////////////////////////////////////////////////
    /*      
    *       DECLARE ALL THR VARIABLES USED IN THIS CONTROLLER.
    */

        /*
         * DATABASE RELATED VARIABLES
         */
        private Connection db_connect;
        // this is the database connection string for SQL query results 

        PreparedStatement ps;
        //PreparedStatement ps2;
        // This is the prepared statement for the SQL query

        private String query;
        //This is the SQL query string

        //private ResultSet query_result;
        // this is the results set for the first
        // SQL results

        //private ResultSet query_result2;
        // this is the results set for the second
        // SQL results

        final String DB_NAME = "testDB";
        // This is the database name



        /*
         * IMPORTANT SESSION VARIABLES
         */

        String post_type; 
        // This is the type of post to create.

        final String Image_Path = "/images/";
        // this relative path from src to the images folder to be
        // appended to the image file name.


        /*
         * IMPORTANT GUI/FXML VARIABLES
         */
        @FXML // fx:id="post_details" 
        private AnchorPane create_post; // Value injected by FXMLLoader

        private Stage this_stage;


        /*
         * Button definitions
         */


        @FXML
        private Button btn_create_details_save;
        // this saves the current create Post Details 



        /*
         *  dynamic Label top form Definitions
         */
        @FXML
        private Label   lbl_stage_title;
        // this displays the stage title



        /*
         *  Textfield top form Definitions
         */


    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /*
    * METHOD DEFINITIONS FROM HERE.
    */

    //===================================================================================================================
    /*
    * define methods from here.
    */





        //@FXML
        @Override
        public void initialize(URL location, ResourceBundle resources)
        {
            // Get the stage title
            // So you can get the type of Post to create
            try 
                {
                    this_stage = (Stage) create_post.getScene().getWindow();
                    post_type=this_stage.getTitle();
                    System.out.println("this_stage_title:"+post_type );
                }// close try

            catch (Exception e)
            {
                e.printStackTrace();
            } //close catch.



            //--------------------------------------------------------------------------------------------------------------------
            /*
             *  This  is the btn_delete_post.setOnAction((event)
             *  This button will cause a process to remove the selected item
             *  by removing the entry in the join table,and then in the main table
             * 
             */

            btn_create_details_save.setOnAction((event) -> 
                    {


                        System.out.println("This causes the post to be created..");

                        //lbl_stage_title.setText("Get the Stage Title");

                    });// close



        }// close public void initialize(URL location, ResourceBundle resources)


    }//createController

I have run this code and it loads the FXML page and displays the label and button, as the exception is getting caught as shown:

java.lang.NullPointerException
    at controller.unilink_home.post.create.unilink_home_post_createController.initialize(unilink_home_post_createController.java:168)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3237)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3194)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3163)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3136)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3113)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3106)
    at controller.unilink_home.test_main.start(test_main.java:15)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
This causes the post to be created..

[if there are other problems problems with the code here is maybe because I have had to shorten some of the file names and paths, but I am across that and do what you need to get this to work...]

Any suggestions or proposed solution to get it to stage title would be really appreciated. I suspect the problem is with the Scene or the Window some how being Null at initialisation time, for that is why when I move this code into the button action:

  this_stage = (Stage) create_post.getScene().getWindow();
  post_type=this_stage.getTitle();
  System.out.println("this_stage_title:"+post_type );

It works, but when I put at this first item in initialise it does not...

Any solutions, suggestions?

Thank you in advance...

kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • still insisting on not using java naming conventions? Does not matter much (except creating a bad habit) when you are doing so at home in a closet, but __does__ matter when asking publicly for coding help: __you__ want to communiate and ask the helpers for part of __their__ time to give it to you for free - so __you__ must make it as easy as possible for anybody to understand what you are doing. – kleopatra Jun 17 '20 at 08:52
  • this is not special to any particular version of javafx, removed the tag – kleopatra Jun 17 '20 at 09:01

1 Answers1

0

Please use proper Java naming conventions. Classes and files should start with a CapitalLetter. Properties, fields, methods should be camelCase and not contain _ underscores.

In your main application, there is no need to create another new Scene post_create_stage just use the primaryStage and before you call primaryStage.show(); you will need to get your CreateController from the FXMLLoader, and set the title... edited for brevity...

public class TestMain extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        // get an instance of FXMLLoader to load your .fxml 
        // AND also get a reference to the controller
        FXMLLoader loader = new FXMLLoader(getClass().getResource("Create.fxml"));

        // Load your .fxml
        Parent postCreate = (Parent) loader.load();

        // Get your controller
        CreateController controller = loader.getController();

        // Set the primaryStage title
        primaryStage.setTitle("Create Event Posting");
        // and now you can pass the title directly to your controller
        controller.setTitle(primaryStage.getTitle());

        primaryStage.setScene(new Scene(postCreate, 300, 275));
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

and in your controller add a field to hold the title passed in and a public method to set it...

public class CreateController implements Initializable {

//..... all your code ....
    // StringProperty is used as it is an Observable and you can attach a listener
    private final StringProperty postType = new SimpleStringProperty();

    //@FXML
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // create a listener for when the stage title is set
        postType.addListener((observable, oldValue, newValue) -> {
            if (null != newValue) {
                System.out.println("this_stage_title:" + postType.get());
                // now postType is set with the passed in primaryStage title and 
                // you can use it as you will
            }
        });

// ..... the rest of your initialize code ....
}

    public void setTitle(String title) {
        postType.set(title);
    }

and the console output from the above code

this_stage_title:Create Event Posting

Process finished with exit code 0
b3tuning
  • 337
  • 2
  • 8
  • If you are trying to re-use your controller, and have 3 values that change its behavior, instead of passing in a title, create an enum for `EVENT, SALE, POST` change StringProperty to ObjectProperty and in the addListener lambda, just `switch` on the `newValue` as one of the enum values. – b3tuning Jun 17 '20 at 08:44
  • Thank you! that worked... I was missing the listener.. and now I have a switch statement that populates a form fields depending on the postType being passed in.... Fortunately I have a session table so I get the ID of the creator... but if I wanted to pass more than one variable, how would I do it? – Flash Jack From Gundagai Jun 18 '20 at 07:12