为什么JavaFX ImageView有时需要BufferedImage来显示任何内容?

时间:2015-07-08 14:55:47

标签: javafx imageview

目前正在尝试将警告图形放置在输入字段旁边。

将ImageView放入位于文件中的Scene Builder中,生成:

    <ImageView fx:id="helpPic" fitHeight="22.0" fitWidth="33.0" layoutX="47.0" layoutY="336.0" onMouseClicked="#warnInfo" pickOnBounds="true" preserveRatio="true">
       <image>
          <Image url="@../../Library/risk-468289_640.png" />
       </image>
    </ImageView>

加载时没有错误,但没有图像。

我正在尝试将其作为控制器的一部分加载:

helpPic.setImage(new Image("Library/risk-468289_640.png"));

没有错误,仍然没有图像。

为了验证它不是图像,我在mspaint中写了一些内容作为jpg并尝试加载它并且它仍然没有显示任何内容。

寻找解决方案,我通过以下方式开展工作:

BufferedImage bufferedImage = ImageIO.read(new File("Library/risk-468289_640.png"));
Image image = SwingFXUtils.toFXImage(bufferedImage, null);
helpPic.setImage(image);

但是,FXML / ImageView需要额外的处理来完成它的工作,这似乎有点奇怪。

编辑:

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));

    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.resizableProperty().setValue(Boolean.FALSE);
    stage.show();
}

1 个答案:

答案 0 :(得分:0)

我无法弄清楚为什么FXML版本不适合你,但我可以给你一个如何工作的描述,这应该足以让你弄清楚发生了什么。

FXMLLoader遇到以@开头的属性值时,它会将其视为资源位置,并将其解析为FXML documentation中所述的网址。这基本上意味着它通过调用

生成URL
new URL(location, spec);

其中locationFXMLLoader的位置属性,而spec是剥离了前导@的属性值。这根据here描述的规则解决。

location的{​​{1}}属性反过来是您传递给FXMLLoader constructorFXMLLoader.setLocation(...)FXMLLoader {{的值3}}。在您的情况下,您使用static创建此网址。我一直认为这意味着“获取一个URL,它从加载这个类的同一个地方加载资源”:显然这是一个非正式的定义,精确的描述是FXMLLoader.load(...) method。粗略地说,如果您提供的字符串不以getClass().getResource("MainWindow.fxml")开头,将会在与该类相同的包中搜索资源;否则它将(通常)在类路径中搜索。 URL 的方案取决于与当前类关联的类加载器。因此,如果您从文件系统运行应用程序,则实际URL将显示为/。如果您从jar文件运行它将看起来像file:///path/to/current/package/MainWindow.fxml(或类似的东西),其中jar:///path/to/jar/file!/package/MainWindow.fxml是定义类的包,package替换为{ {1}}。

因此,如果.的{​​{1}}属性具有/方案,那么事情应该基本上起作用(假设文件位于正确的位置)。你基本上做

location

(第一个参数实际上是现有的FXMLLoader对象,而不是file:)。由于new URL("file:///path/to/current/package/MainWindow.fxml", "../../Library/risk-468289_640.png"); 方案可以很好地理解父目录符号URL,因此事情应该正常工作。

另一方面,如果你的类是由jar类加载器加载的,那么事情可能会破坏:

String

如果此处的父目录级别多于包级别,则jar类加载器将无法创建任何有意义的内容。 (file:方案意味着“从jar文件加载”,但您试图跳出jar文件条目层次结构的顶层。)

听起来您正在尝试访问类路径之外的文件资源:使用FXML资源位置执行此操作并不能保证成功,因为它实际上尝试使用..来加载资源,一般只知道类路径中的事情。具体来说,使用jar类加载器,它将失败。

您可以在new URL("jar:///path/to/jar/file!/package/MainWindow.fxml", "../../Library/risk-468289_640.png"); 方法中添加一些调试,以尝试查看正在发生的事情:

jar:

至少应该让您看到ClassLoader尝试做什么,并且您应该能够看到生成的网址是否有意义。

如果从文件系统(而不是从类路径)加载start,最好显式创建文件URL(您必须在Java代码中,即在控制器中):< / p>

URL fxmlURL = getClass().getResource("MainWindow.fxml") ;
System.out.println(fxmlURL.toExternalForm());
URL resourceURL = new URL(fxmlURL, "../../Library/risk-468289_640.png");
System.out.println(resourceURL.toExternalForm());

Parent root = FXMLLoader.load(fxmlURL);