1

I am having a problem changing scenes JavaFX. When I try to switch scenes, I get a null pointer exception, however I used the debugger to debug it, and it is telling me that the stage pointer is null. I noticed that it does not find the start method's constructor declaration of stage, so I made a variable for the entire class. I am unsure why this stage pointer is null, since I did declare the variable in the class.

Here is the method from the main controller that switches scenes:

onstart.changeScene("password.fxml");

And here is the class OnStart, which is used to switch scenes:

public class OnStart extends Application{
Parent root;
private Stage stage;
//private AnchorPane mainLayout;
//private HashMap<String, Pane> screenMap = new HashMap<>();
private Scene main;
FXMLLoader loader = new FXMLLoader();

@Override
public void start(Stage stage) throws Exception{
    this.stage = stage;
    root = loader.load(getClass().getResource("mainmenu.fxml"));

    main = new Scene(root);

    this.stage.setTitle("Photo Encryptor 9000");
    this.stage.setScene(main);
    this.stage.show();
}

public Parent getRoot() {
    return root;
}

public Scene getScene() { return main; }

public void changeScene(String fxml) throws IOException {
    root = loader.load(
            getClass().getResource(fxml));
    stage.getScene().setRoot(root);
}
}

Also here is the error(line 44 is the stage.getScene.setRoot(root) method):

Caused by: java.lang.NullPointerException
at com.example.helloworld.OnStart.changeScene(OnStart.java:44)
at com.example.helloworld.MainController.encryptpress(MainController.java:99)

MainController:

public class MainController implements Initializable{

public String path, name;
private String passwordPlainText;
private boolean hasname;
private File f;
FileWriter out;
OnStart onstart = new OnStart();
BufferedImage image;
int widthofimage, heightofimage, numberofpixils;
AES aes = new AES();
@FXML
private TextField passwordtextbox;
FileReader read;


@FXML
private AnchorPane rootpane;

@Override
public void initialize(URL url, ResourceBundle rb){
}

@FXML
private void encryptpress(ActionEvent event) throws Exception {
    //byte[] converter; //sample of encrypting and decrypting
    //String output = "hello";
    //converter = output.getBytes();
    //System.out.println(output);
    //converter = aes.encrypt(output, "noooo");
    //System.out.println(converter);
    //output = aes.decrypt(converter, "noooo");
    //System.out.println(output);

    //File chooser
    FileChooser fileChooser = new FileChooser();
    fileChooser.setTitle("Open Resource File");
    fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("JPEG Files", "*.jpg"));
    f = fileChooser.showOpenDialog(null);    //f is the image
    //Checks if a jpg file was chosen
    if(f == null) {//if a file wasn't chosen...
        AlertBox.display("Error", "No file was chosen");
        return;
    }
    read = new FileReader();
    out = new FileWriter("passwords.txt", true);
    path = f.getAbsolutePath();//gets absolute path of file
    name = f.getName();//gets name of file
    System.out.println("Does file exist in passwords file: " + read.checkforfile(name)); //test - should output true if a file with name exists

    if( read.checkforfile(name) ){ //goes back to parent node
        if( read.hasHash(name) ){
            AlertBox.display("Error", "This filename already has a password.");
            //if true, then go back to main menu and display: "This filename already has a password."
            Parent parent = onstart.getRoot(); //Not sure if this gets the pointer to the root or just a copy of the root
            Scene parentscene = onstart.getScene();
            Stage window = (Stage) ((Node)event.getSource()).getScene().getWindow();
            window.setScene(parentscene);
            window.show();
            return;
        }
        hasname = true; //maybe close this automatically
        //skips the addname process if hasname is true
    }else { //adds the name of the image to the file if the image does not already exist

        hasname = false; // waits to write the name just incase the user exits out of the program early without choosing a password
    }

    if(hasname == false){
        out.write(name);
    }
    //System.out.println(name);
    out.write(name);

    image = ImageIO.read(f);
    if(onstart.getRoot() != null) {System.out.println("Root is clear");}
    if(onstart.getStage() != null) {System.out.println("Stage is clear");}
    if(onstart.getScene() != null) {System.out.println("Scene is clear");}
    onstart.changeScene("password.fxml");//////////////Error



    //This copies the file and places it in the same directory
    String newfile = "Encrypted" + f.getName();
    File EncryptedImage = new File(newfile);
    BufferedImage originalImage = ImageIO.read(f);
    BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
    widthofimage = originalImage.getWidth();
    heightofimage = originalImage.getHeight();
    numberofpixils = widthofimage * heightofimage;
    int add = 0;
    byte[] bytes = new byte[numberofpixils];
    for (int x = 0; x < originalImage.getWidth(); x++) {
        for (int y = 0; y < originalImage.getHeight(); y++) {
            bytes[add] = (byte) originalImage.getRGB(x, y);
            add++;
        }
    }
    String s = new String(bytes);
    String passwordtest = "password";
    //s = aes.encrypt(s, passwordtest); //passwordplaintext is real passowrd holder
    bytes = s.getBytes();

    add = 0;

    for (int x = 0; x < originalImage.getWidth(); x++) {
        for (int y = 0; y < originalImage.getHeight(); y++) {
            newImage.setRGB(x, y, bytes[add]);
            add++;
        }
    }
    ImageIO.write(newImage, "JPG", EncryptedImage);
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //ImageIO.write(newImage, "JPG", f2);//this creates a new image that is now encrypted
    //System.out.println(image);

}


/*@FXML
private void dgxsd(ActionEvent event){
    String test = "Hello";
    String passwordtest = "password";
    System.out.println(test);
    test = aes.encrypt(test, passwordtest); //passwordplaintext is real passowrd holder
    System.out.println(test);
    test = aes.decrypt(test, passwordtest);
    System.out.println(test);
}*/


@FXML
private void decryptpress(ActionEvent event) throws IOException {
    //if passwords.txt is not empty: AnchorPane pane = FXMLLoader.load(getClass().getResource("password2.fxml"));
    FileChooser fileChooser = new FileChooser();
    fileChooser.setTitle("Open Resource File");
    fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("JPEG Files", "*.jpg"));
    File f = fileChooser.showOpenDialog(null);
    if(f == null) {//if a file wasn't chosen...
        AlertBox.display("Error", "No file was chosen");
        return;
    }
    read = new FileReader();
    out = new FileWriter("passwords.txt", true);
    path = f.getAbsolutePath();//gets absolute path of file
    name = f.getName();//gets name of file
    System.out.println("Does file exist: " + read.checkforfile(name)); //test - should output true if a file with name exists
}


@FXML
private void Createpassword(ActionEvent event) throws IOException {
    passwordPlainText = passwordtextbox.getText();
    System.out.println(passwordPlainText);
    BufferedImage image = ImageIO.read(f);


   // doAESEncryption(passwordPlainText);
}
  • It didn't help too much, I don't know how it became null. – Submersed24 May 02 '19 at 16:10
  • That is just the method in the main controller calling the getScene method – Submersed24 May 02 '19 at 16:12
  • either stage is null (unlikely), `getScene()` is returning null, or `root` is null. – Benjamin Urquhart May 02 '19 at 16:13
  • I declared all of the variables to these: this.stage = stage; root = loader.load(getClass().getResource(fxml)); main = new Scene(root); I don't see why it's giving me a null. – Submersed24 May 02 '19 at 16:34
  • You haven't posted your MainController class, and you're not doing a mainController.setOnStart() in the Application class. So we can only assume that you're doing a `public MainController() { this.onStart = new OnStart(); }` which means mainController#onStart is not the same Application onStart and therefore has a null stage. Post your MainController code for more info. – kendavidson May 02 '19 at 16:37
  • I just added it – Submersed24 May 02 '19 at 16:46

1 Answers1

2

@kendavidson is Correct the reason you are getting null is this line in your MainController class your have this line

OnStart onstart = new OnStart();

The reason for the null pointer is that you are creating a new instance of the class when you do that and in that instance root is set to null

To remedy this problem create a method that looks like this in your MainController class

public void setOnStartReference(OnStart onStartReference){
    onstart = onStartReference;
}

and remove the = new OnStart(); at the top of your MainController class so it now should look like this

OnStart onstart;

Now in your OnStart class you need to set the reference before you can call anything in the OnStart class like so

MainController controller = loader.getController();
controller.setOnStartReference(this);

But make sure to put that below the loader.load...

Matt
  • 3,052
  • 1
  • 17
  • 30