JavaFX ImageView 不更新 [英] JavaFX ImageView not updating

查看:29
本文介绍了JavaFX ImageView 不更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我试图将图像加载并保存到一个 imageView 中,其中图像的位置是通过文件浏览器选择的.我已经为此工作了几天,如果我无法修复它,我会中风.我已经尝试了我能想到的一切.提前感谢您的帮助.

更新:

这是我的主要课程:

公共类主要扩展应用程序{私人舞台primaryStage;私有 BorderPane 根布局;公共 Main(){}@覆盖公共无效开始(阶段主要阶段)抛出异常{this.primaryStage = 初级阶段;this.primaryStage.setTitle("请帮忙");初始化根布局();显示屏幕();}公共无效initRootLayout(){尝试{FXMLLoader 加载器 = 新的 FXMLLoader();loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));rootLayout = (BorderPane) loader.load();场景场景 = 新场景(rootLayout);primaryStage.setScene(场景);RootLayout 控制器 = loader.getController();控制器.setMain(this);主舞台.show();}catch(异常 e){e.printStackTrace();}}公共无效显示屏幕(){try{FXMLLoader 加载器 = 新的 FXMLLoader();loader.setLocation(Main.class.getResource("view/sample.fxml"));BorderPane 示例 = (BorderPane)loader.load();rootLayout.setCenter(sample);控制器控制器 = loader.getController();控制器.setMain(this);}catch (异常 e){e.printStackTrace();}}公共阶段 getPrimaryStage(){return primaryStage;}公共静态无效主要(字符串[]参数){启动(参数);}}

这是根布局:

公共类 RootLayout {私人主主;私有控制器控制器 = 新控制器();public void setMain(Main main){this.main = main;}@FXML私人无效句柄打开(){FileChooser fileChooser = new FileChooser();FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter("PNG 文件 (*.png)","*png");fileChooser.getExtensionFilters().add(extensionFilter);文件文件 = fileChooser.showOpenDialog(main.getPrimaryStage());如果(文件!= null){controller.updateImage(file.toURI().toString());}}}

这里是控制器:

公共类控制器实现可初始化{@FXMLImageView imageView = new ImageView();字符串图像URL;主要主要=新主要();公共无效setMain(主要主要){this.main = 主要;}公共无效更新图像(字符串网址){if(url.length()>=1){图片图片=新图片(网址);imageView.setImage(图像);System.out.println(url);}别的{System.out.println(url);System.out.println("图片无效");}}@覆盖公共无效初始化(URL位置,ResourceBundle资源){}}

解决方案

两件事:

  1. 从不分配一个其值将由 FXMLLoader 注入的字段(例如 @FXML 字段).这样做充其量是对资源的浪费,而在最坏的情况下会引入一些细微的错误.例如,如果您未初始化 imageView 字段,您将得到一个 NullPointerException,这表明您的设置存在问题.但是,由于您确实初始化了该字段,因此您不会收到任何错误,并且会产生代码正常工作的错误印象.

  2. 在您的 RootLayout 控制器类中,您有:

    <块引用>

    私有控制器控制器 = new Controller();

    您刚刚创建的 Controller 实例未链接到任何 FXML 文件.并且由于您初始化了 imageView 字段(请参见第一点),您最终会更新一个未在任何地方显示的 ImageView ;这是不初始化所述字段会很好地表明存在问题的地方.解决方法是将FXMLLoader创建的Controller实例传递给另一个FXMLLoader创建的RootLayout实例.

    另外,你在同一个班级:

    <块引用>

    Main main = new Main();

    这也是不必要的,因为创建的 Main 实例都不是正确的实例,并且几乎立即被对 #setMain(Main) 的调用所取代.p>

<小时>

假设您的 FXML 文件(您没有提供)是正确的,Java 类应该看起来更像:

Main.java

public class Main extends Application {私人舞台primaryStage;私有 BorderPane 根布局;私有 RootLayout rootLayoutController;公共主要(){}@覆盖公共无效开始(阶段主要阶段)抛出异常{this.primaryStage = 初级阶段;this.primaryStage.setTitle("请帮忙");初始化根布局();显示屏幕();}公共无效initRootLayout(){尝试 {FXMLLoader 加载器 = 新的 FXMLLoader();loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));rootLayout = (BorderPane) loader.load();场景场景 = 新场景(rootLayout);primaryStage.setScene(场景);//将 RootLayout 实例存储在字段中以便 #showScreen()//可以引用rootLayoutController = loader.getController();rootLayoutController.setMain(this);主舞台.show();} 捕捉(异常 e){e.printStackTrace();}}公共无效显示屏幕(){尝试 {FXMLLoader 加载器 = 新的 FXMLLoader();loader.setLocation(Main.class.getResource("view/sample.fxml"));BorderPane 示例 = (BorderPane) loader.load();rootLayout.setCenter(sample);控制器控制器 = loader.getController();控制器.setMain(this);//在 RootLayout 实例上设置 Controller 实例rootLayoutController.setController(控制器);} 捕捉(异常 e){e.printStackTrace();}}公共阶段 getPrimaryStage() {返回初级阶段;}公共静态无效主要(字符串[]参数){启动(参数);}}

RootLayout.java

公共类 RootLayout {私人主主;私有控制器控制器;公共无效setMain(主要主要){this.main = 主要;}公共无效setController(控制器控制器){this.controller = 控制器;}@FXML私人无效句柄打开(){FileChooser fileChooser = new FileChooser();//注意扩展名应以*"为前缀.FileChooser.ExtensionFilter extensionFilter =new FileChooser.ExtensionFilter("PNG 文件 (*.png)", "*.png");fileChooser.getExtensionFilters().add(extensionFilter);文件文件 = fileChooser.showOpenDialog(main.getPrimaryStage());如果(文件!= null){controller.updateImage(file.toURI().toString());}}}

Controller.java

public class Controller 实现 Initializable {@FXML 图像视图图像视图;//保持未初始化,将被注入字符串图像URL;主要主要;公共无效setMain(主要主要){this.main = 主要;}公共无效更新图像(字符串网址){如果 (url.length() >= 1) {图片图片=新图片(网址);imageView.setImage(图像);System.out.println(url);} 别的 {System.out.println(url);System.out.println("图片无效");}}@覆盖公共无效初始化(URL位置,ResourceBundle资源){}}

注意:没有测试新代码.

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) {
    }
}

解决方案

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.

这篇关于JavaFX ImageView 不更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆