-1

So I'm trying to load and save Images into an imageView where the location of the image is chosen through a file browser. I've been working on this for several days now and I'm gonna have a stroke if I can't get it fixed. I've tried everything I can think of. Thank you in advance for helping.

UPDATED:

Here is my main class:

public class Main extends Application {
    private Stage primaryStage;
    private BorderPane rootLayout;
    public Main(){}
    @Override
    public void start(Stage primaryStage) throws Exception{
      this.primaryStage = primaryStage;
      this.primaryStage.setTitle("Help Please");
      initRootLayout();
      showScreen();
    }
    public void initRootLayout(){
        try{
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));
            rootLayout = (BorderPane) loader.load();
            Scene scene = new Scene(rootLayout);
            primaryStage.setScene(scene);
            RootLayout controller = loader.getController();
            controller.setMain(this);
            primaryStage.show();
        }catch(Exception e ){e.printStackTrace();}
    }
    public void showScreen(){
        try{FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("view/sample.fxml"));
        BorderPane sample = (BorderPane)loader.load();
        rootLayout.setCenter(sample);
        Controller controller = loader.getController();
        controller.setMain(this);
        }catch (Exception e){e.printStackTrace();}
    }
    public Stage getPrimaryStage(){return primaryStage;}
    public static void main(String[] args) {
        launch(args);
    }
}

Here is the rootLayout:

public class RootLayout {
    private Main main;
    private Controller controller = new Controller();
    public void setMain(Main main){this.main = main;}
    @FXML
    private void handleOpen(){
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(
                "PNG files (*.png)","*png");
        fileChooser.getExtensionFilters().add(extensionFilter);
        File file = fileChooser.showOpenDialog(main.getPrimaryStage());
        if(file!= null){
            controller.updateImage(file.toURI().toString());
        }
    }
}

And here is the controller:

public class Controller implements Initializable {
    @FXML
    ImageView imageView = new ImageView();
    String imageURL;
    Main main = new Main();
    public void setMain(Main main){
        this.main = main;
    }
    public void updateImage(String url){
        if(url.length()>=1){
            Image image = new Image(url);
            imageView.setImage(image);
            System.out.println(url);
        }
        else{
            System.out.println(url);
            System.out.println("image invalid");
        }
    }
    @Override
    public void initialize(URL location, ResourceBundle resources) {
    }
}
  • 1
    You are using the @FXML tag for the imageView meaning that you do not have to create a new ImageView. Here's just a tip, the [accepted answer](https://stackoverflow.com/questions/30210170/is-fxml-needed-for-every-declaration) explains well why this is the case. – Robert Dec 09 '19 at 17:20
  • 1
    How did you get your fxml to load? If the first code snippet is indeed from your controller, the fact that you're passing `null` to the `updateImage` method should result in a `NullPointerException` at `if(url.length()<=1){` perventing you from properly loading the scene. – fabian Dec 09 '19 at 17:45
  • 1
    Could you please create a [mre] that demonstrates the problem, then add it to your question via an [edit]? The example should be minimal, but _complete_, which means we should be able to copy the code to our machines and execute it with little to no modifications. – Slaw Dec 09 '19 at 21:12
  • @Slaw I have now updated it to be a minimal reproducible example now please help me if you can. thanks – Nina Walker Dec 11 '19 at 16:13
  • @Robert Thank you for your response. I have since removed the unnecessary creation of a new ImageView. It did not change the problem. If you have any more help that would be great. – Nina Walker Dec 11 '19 at 16:15
  • @Fabian Thank you for your comment. When I recreated the problem in another file I got the errors you were talking about and have since fixed them. I would still greatly appreciate further help you can offer. – Nina Walker Dec 11 '19 at 16:16

1 Answers1

1

Two things:

  1. Never assign a field whose value is to be injected by an FXMLLoader (e.g. @FXML fields). Doing so is a waste of resources at best and introduces subtle bugs at worst. For instance, if you were to leave the imageView field uninitialized you'd be getting a NullPointerException which would indicate a problem with your setup. Since you do initialize the field, however, you don't get any errors and there's a false impression of the code working.

  2. In your RootLayout controller class, you have:

    private Controller controller = new Controller();
    

    That instance of Controller you just created is not linked to any FXML file. And since you initialize the imageView field (see first point) you end up updating an ImageView which is not being displayed anywhere; this is where not initializing said field would have given a nice indication of there being a problem. The solution is to pass the Controller instance created by the FXMLLoader to the RootLayout instance created by the other FXMLLoader.

    Also, in the same class you have:

    Main main = new Main();
    

    Which is also unnecessary since the created instance of Main is both not the correct instance and is replaced by the call to #setMain(Main) almost immediately.


Assuming your FXML files (which you did not provide) are correct, the Java classes should look more like:

Main.java

public class Main extends Application {

  private Stage primaryStage;
  private BorderPane rootLayout;
  private RootLayout rootLayoutController;

  public Main() {}

  @Override
  public void start(Stage primaryStage) throws Exception {
    this.primaryStage = primaryStage;
    this.primaryStage.setTitle("Help Please");
    initRootLayout();
    showScreen();
  }

  public void initRootLayout() {
    try {
      FXMLLoader loader = new FXMLLoader();
      loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));
      rootLayout = (BorderPane) loader.load();
      Scene scene = new Scene(rootLayout);
      primaryStage.setScene(scene);

      // store RootLayout instance in field so #showScreen()
      // can reference it
      rootLayoutController = loader.getController();
      rootLayoutController.setMain(this);

      primaryStage.show();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void showScreen() {
    try {
      FXMLLoader loader = new FXMLLoader();
      loader.setLocation(Main.class.getResource("view/sample.fxml"));
      BorderPane sample = (BorderPane) loader.load();
      rootLayout.setCenter(sample);
      Controller controller = loader.getController();
      controller.setMain(this);

      // set Controller instance on RootLayout instance
      rootLayoutController.setController(controller);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public Stage getPrimaryStage() {
    return primaryStage;
  }

  public static void main(String[] args) {
    launch(args);
  }
}

RootLayout.java

public class RootLayout {

  private Main main;
  private Controller controller;

  public void setMain(Main main) {
    this.main = main;
  }

  public void setController(Controller controller) {
    this.controller = controller;
  }

  @FXML
  private void handleOpen() {
    FileChooser fileChooser = new FileChooser();
    // Note extensions should be prefixed with "*."
    FileChooser.ExtensionFilter extensionFilter =
        new FileChooser.ExtensionFilter("PNG files (*.png)", "*.png");
    fileChooser.getExtensionFilters().add(extensionFilter);
    File file = fileChooser.showOpenDialog(main.getPrimaryStage());
    if (file != null) {
      controller.updateImage(file.toURI().toString());
    }
  }
}

Controller.java

public class Controller implements Initializable {

  @FXML ImageView imageView; // leave uninitialized, will be injected
  String imageURL;
  Main main;

  public void setMain(Main main) {
    this.main = main;
  }

  public void updateImage(String url) {
    if (url.length() >= 1) {
      Image image = new Image(url);
      imageView.setImage(image);
      System.out.println(url);
    } else {
      System.out.println(url);
      System.out.println("image invalid");
    }
  }

  @Override
  public void initialize(URL location, ResourceBundle resources) {}
}

Note: Did not test new code.

Slaw
  • 37,820
  • 8
  • 53
  • 80
  • Thank you for your response. I changed the things you were telling me to, but now what I get is a NullPointerException pointing to the `controller.updateImage(file.toURI().toString());` in the handleOpen() in the RootLayoutController. I know you mentioned that that would be happening if i didnt initialize the imageview but how would I point it to the right place so that I dont have to get the NullPointer – Nina Walker Dec 13 '19 at 17:49
  • I just created some mock FXML files based on the given code; I cannot reproduce the `NullPointerException` and the `ImageView` is updated correctly. Are you sure you included the `rootLayoutController.setController(controller);` code? And your FXML file has an `fx:id="imageView"` attribute for the `ImageView` element, correct? – Slaw Dec 13 '19 at 18:08