无法更改默认 Java 图片 (JFrame.setIconImage)

Can't Change Default Java Image (JFrame.setIconImage)

我正在尝试更改 Java 应用程序的图标,但似乎没有任何效果。

我正在尝试使用以下资源路径获取图像:

getClass().getResource("/AppIcon.png")

有时我会收到类似 URL 未找到的错误。

用于表单图标的图像可以是任何图像,但必须作为 Image 类型加载(不是 ImageIcon类型)。 JFrame#setIconImage() 方法将 auto-size 加载图像。这里只有几种方法。这些示例假定代码驻留在 扩展 JFrame:

的 class 中

示例 #1:

try {
    /* For a Form's title bar icon....
       Don't use this for animated .gif images otherwise your GUI will 
       freeze. I'm not exactly sure why but it seems as though the gif 
       frames continuously cycle as though in an infinite loop. If you 
       want to use an animated .gif image as a Form's title bar icon 
       then don't use Toolkit, use ImageIO.read() instead since it will 
       only utilize the first gif frame as the image.                */
    // Be sure to set the path string to your specific resources directory.
    this.setIconImage(java.awt.Toolkit.getDefaultToolkit()
            .getImage(getClass().getResource("/resources/images/Apple/png").getFile()));
}
catch (java.lang.NullPointerException ex) {
    // Do what you want with caught exception.
    ex.printStackTrace();
}

示例 #2:

try {
    /* Can be used to also display an animated gif for the Form's Title 
       bar icon but only the first gif frame is utilized.         */
    // Be sure to set the path string to your specific resources directory.
    File pathToFile = new File(getClass().getResource("/resources/images/Apple.png").getFile());
    Image image = ImageIO.read(pathToFile);
    this.setIconImage(image);
}
catch (IOException ex) {
    // Do what you want with caught exception.
    ex.printStackTrace();
}

更新:

如@AndrewThompson 在评论中所述,上述两个示例将无法按预期从 JAR 文件中运行。如果 运行 通过 IDE 它们将工作,但实际上除了测试之外没有任何好处。要在分布式 JAR 文件中使用上面的两个示例,请参阅 Example #3Example #4:

示例 #3:

try {
    /* For a Form's title bar icon.... To be used in a distributive JAR. 
       Don't use this for animated .gif images otherwise your GUI will 
       freeze. I'm not exactly sure why but it seems as though the gif 
       frames continuously cycle as though in an infinite loop. If you 
       want to use an animated .gif image as a Form's title bar icon 
       then don't use Toolkit, use ImageIO.read() instead since it will 
       only utilize the first gif frame as the image.                */
    // Be sure to set the path string to your specific resources directory.
    java.net.URL url = getClass().getResource("/resources/images/Apple.png");
    this.setIconImage(java.awt.Toolkit.getDefaultToolkit().getImage(url));
}
catch (java.lang.NullPointerException ex) {
    // Do what you want with caught exception.
    ex.printStackTrace();
}

示例 #4:

try {
    /* For a Form's title bar icon.... To be used in a distributive JAR. 
       Can be used to also display an animated gif for the Form's Title 
       bar icon but only the first gif frame is utilized.         */
    // Be sure to set the path string to your specific resources directory.
    java.net.URL url = getClass().getResource("/resources/images/Apple.png");
    Image image = ImageIO.read(url);
    this.setIconImage(image);
}
catch (IOException ex) {
    // Do what you want with caught exception.
    ex.printStackTrace();
}

甚至不用理会示例 #1 和 #2,它们现在仅供参考。只需使用示例 #3 或示例 #4。两者都可以在 IDE 或分布式 JAR 文件中使用。

解决方案; 一切都适用于 windows 但我正在使用 Mac :D 所以我开始四处查看任务栏 class 自带的 awt 包并找到了解决方案(感谢 flohall

try {
    var image = new ImageIcon(Objects.requireNonNull(Main.class.getResource("/AppIcon.png")));
    frame.setIconImage(image.getImage());
    if (System.getProperty("os.name").startsWith("Mac") || System.getProperty("os.name").startsWith("Darwin")) {
        Taskbar taskbar = Taskbar.getTaskbar();
        try {
            taskbar.setIconImage(image.getImage());
        } catch (final UnsupportedOperationException e) {
            System.out.println("Can't set taskbar icon.");
        } catch (final SecurityException e) {
            System.out.println("Warning. Can't set taskbar icon due to security exceptions.");
        }
    }
} catch (NullPointerException e) {
    e.printStackTrace();
}

所以我们告诉任务栏使用 built-in 在 taskbar.setIconImage(image.getImage()); 上使用 awt 任务栏 class 更改其图标。这解决了我需要的大部分事情。