JavaFX ImageView not updating

痞子三分冷 提交于 2020-01-14 07:01:27

问题


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:


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.



来源:https://stackoverflow.com/questions/59253649/javafx-imageview-not-updating

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!