首页 > 解决方案 > 我无法加载图像来更改窗口 JavaFX 的图标

问题描述

我试图用 JavaFx 制作一个带有图标的窗口,但它不起作用。我不知道为什么?我一直在使用 InputStream 进行测试,但我也遇到了错误。我使用 URL,它也不起作用。请帮忙

主类:

package fr.fireblaim.firelauncherlib_test;

import fr.fireblaim.firelauncherlib.WindowOptions;
import fr.fireblaim.firelauncherlib.graphics.Base;
import fr.fireblaim.firelauncherlib.utils.ResourceLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Main extends Base {

    private WindowOptions windowOptions = new WindowOptions(1280, 720,  "Launcher Test", true, StageStyle.UNDECORATED);

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

    @Override
    public void start(Stage stage) throws Exception {
        Scene scene = new Scene(new LauncherPanel(windowOptions));

        setupWindow(stage, scene, windowOptions, ResourceLoader.loadImage("icon.png"));
    }

}

资源加载器类:

package fr.fireblaim.firelauncherlib.utils;

import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

public class ResourceLoader {

    private static String resourceLocation = "resources/";

    public static Image loadImage(String file) {
        try {
            BufferedImage image = ImageIO.read(new URL( "file:" + getResourceLocation() + file));
            return SwingFXUtils.toFXImage(image, null);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void setResourceLocation(String resourceLocation) {
        ResourceLoader.resourceLocation = resourceLocation;
    }

    public static String getResourceLocation() {
        return resourceLocation;
    }
}

基类:

package fr.fireblaim.firelauncherlib.graphics;

import fr.fireblaim.firelauncherlib.WindowOptions;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import javax.swing.*;
import java.awt.*;

public abstract class Base extends Application {

    private Point point = new Point();

    public abstract void start(Stage stage) throws Exception;

    protected void setupWindow(Stage stage, Scene scene, WindowOptions windowOptions) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
            System.err.println("[FireLauncherLib] Can't setup the window:\n" + e);
        }

        stage.initStyle(windowOptions.getStageStyle());
        stage.setResizable(false);
        stage.setTitle(windowOptions.getTitle());
        stage.setWidth(windowOptions.getWidth());
        stage.setHeight(windowOptions.getHeight());
        stage.setAlwaysOnTop(true);

        stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                Platform.exit();
                System.exit(0);
            }
        });

        if(windowOptions.isMovable()) {
            scene.setOnMousePressed(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                    point.x = (int)(stage.getX() - event.getScreenX());
                    point.y = (int)(stage.getY() - event.getScreenY());
                }
            });

            scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                    stage.setX(event.getScreenX() + point.x);
                    stage.setY(event.getScreenY() + point.y);
                }
            });
        }

        stage.setScene(scene);

        stage.show();
    }

    protected void setupWindow(Stage stage, Scene scene, WindowOptions windowOptions, Image icon) {
        setupWindow(stage, scene, windowOptions);
        stage.getIcons().clear();
        stage.getIcons().add(icon);
    }

}

我有这个错误:

javax.imageio.IIOException: Can't get input stream from URL!
    at javax.imageio.ImageIO.read(ImageIO.java:1401)
    at fr.fireblaim.firelauncherlib.utils.ResourceLoader.loadImage(ResourceLoader.java:17)
    at fr.fireblaim.firelauncherlib_test.Main.start(Main.java:24)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$10(GtkApplication.java:245)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.FileNotFoundException: resources/icon.png (Aucun fichier ou dossier de ce type)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:90)
    at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:188)
    at java.net.URL.openStream(URL.java:1068)
    at javax.imageio.ImageIO.read(ImageIO.java:1399)
    ... 11 more
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at javafx.stage.Stage$4.onChanged(Stage.java:696)
    at com.sun.javafx.collections.TrackableObservableList.lambda$new$0(TrackableObservableList.java:45)
    at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
    at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
    at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
    at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
    at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
    at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
    at java.util.AbstractList.add(AbstractList.java:108)
    at fr.fireblaim.firelauncherlib.graphics.LauncherBase.setupWindow(LauncherBase.java:70)
    at fr.fireblaim.firelauncherlib_test.Main.start(Main.java:24)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$10(GtkApplication.java:245)
    at java.lang.Thread.run(Thread.java:748)

我使用 Intellij IDEA 2019.3.4 Ultimate

资源结构:

src资源图标.png

标签: javauser-interfacejavafxwindow

解决方案


从您的代码看来 - 当您使用“文件:”协议时 - 您希望图像位于文件系统上的目录中。那么为什么不从文件而不是 URL 更改调用负载:

File f = new File(getResourceLocation(), file);
ImageIO.read(f)

然后,您可以通过调用 / 打印检查 Java 认为这些文件来自何处来解决目录位置问题:

f.getAbsolutePath();
f.exists();

或者,如果这些图像与您的代码在同一个 jar 中,您应该使用 getClass().getResourceAsStream() 来定位 InputStream 以传递给 ImageIO.read(is)。


推荐阅读