在OS X上使用Java Swing设置默认应用程序图标图片

14

我正在尝试设置一个Jar文件的图标图片:

setIconImage(new ImageIcon(getClass().getResource("logo.png")).getImage());

在运行Mac OS X 10.7.4时,我遇到了以下错误:

Jun 28 15:21:40 (my dhcp) java[73383] <Error>: CGContextGetCTM: invalid context 0x0
Jun 28 15:21:40 (my dhcp) java[73383] <Error>: CGContextSetBaseCTM: invalid context 0x0
Jun 28 15:21:40 (my dhcp) java[73383] <Error>: CGContextGetCTM: invalid context 0x0
Jun 28 15:21:40 (my dhcp) java[73383] <Error>: CGContextSetBaseCTM: invalid context 0x0
Jun 28 15:21:40 (my dhcp) java[73383] <Error>: CGContextGetCTM: invalid context 0x0
Jun 28 15:21:40 (my dhcp) java[73383] <Error>: CGContextSetBaseCTM: invalid context 0x0

1
你是想设置 Dock 图标还是应用程序菜单栏图标? - TeaCupApp
1
请编辑您的问题以包含这些要求。 - trashgod
请参阅苹果公司的Mac Java开发指南 - Arjan
这回答解决了你的问题吗?如何更改Java程序的Dock图标? - bric3
更好的答案适用于JDK 9+,请参见此处https://dev59.com/Im025IYBdhLWcg3wblg3#56924202 - bric3
显示剩余6条评论
6个回答

30

setIconImage方法无法设置jar文件图标。它将设置JFrame的最小化窗口所显示的图标。jar图标(控制Finder图标和Dock应用程序图标)不能在jar文件本身中设置。您只能获得操作系统提供的默认图标。您需要使用像JarBundler(适用于OS X)或Launch4J(适用于Windows)等工具进行封装。

您可以在应用程序运行时设置应用程序Dock图标,请参见com.apple.eawt.Application.setDockIconImage。但这并不完美,因为当您双击jar文件时,它会在Dock中使用通用的Java图标启动,并且只有在Java代码开始运行后弹跳一两次后才会切换到您的自定义图标。此外,我认为它不会为未运行的jar文件设置Dock图标(您无法将jar文件拖入Dock中 - 对我来说似乎无效)。

以下是演示您可以设置的不同图像的代码:

import com.apple.eawt.Application;
import javax.swing.*;

class SetIcon extends JFrame {

    SetIcon() {
        setIconImage(new ImageIcon("doc.png").getImage());
        Application.getApplication().setDockIconImage(
            new ImageIcon("app.png").getImage());
    }

    public static void main(String args[]) {
        SetIcon s = new SetIcon();
        s.setVisible(true);
    }
}

它被安装在每台Mac上。 - Keith Randall
3
+1 对于 com.apple.eawt.Application,这是我之前忽略的。 - trashgod
3
谢谢!这解决了我的问题。附注:我需要执行以下操作:Application.getApplication().setDockIconImage(new ImageIcon(getClass().getResource("/logo.png")).getImage()); - rhombidodecahedron
3
com.apple.eawt.Application.setDockIconImage现在已经失效了。有任何关于2015年可以查找此内容的想法吗? - Mshnik
1
在此澄清一下,在Mac上运行Java应用程序时,似乎有两个“图标”起作用。默认情况下,Java进程本身会获得一个图标(Java CPU),然后您创建的新窗口,每个新窗口都有“它自己的图标”,这个图标直到你将该窗口最小化才会显示出来。因此,请注意您设置的图标,本答案描述如何影响“主”图标,该图标显然始终可见。奇怪的事情。 - rogerdpack
显示剩余3条评论

9

这里是关于如何在纯Java应用程序中添加MacOSX Dock图标的最终解决方案:

public boolean exists(String className)
{
    try {
        Class.forName( className, false, null );
        return true;
    }
    catch (ClassNotFoundException exception) {
        return false;
    }
}

public void setIcon( BufferedImage icn )
{
    if ( exists( "com.apple.eawt.Application" ) )
    {
        com.apple.eawt.Application.getApplication().setDockIconImage( icn );
    }
}

这个方法会自动检查类是否可用,然后执行setDockIconImage() 方法。我发现这种方法非常有效,并且不会影响其他平台。

@rogerdpack 当然这是一个选项,但是这个检查确保setDockIconImage()可以安全地执行。 - mvreijn

6
你可以将.icns文件放置在应用程序包的Contents/Resources目录中,并在Info.plist文件中引用它。例如,名为ApplicationName.icns的文件将由以下形式的<dict>条目引用:
<key>CFBundleIconFile</key>
<string>ApplicationName.icns</string>

一些相关细节在这里提到。


有没有不将它打包成 .app 的方法来完成这个任务?我们选择使用 Java 开发这项技术,以便我们可以向所有用户分发一个文件,而不受平台的限制。 - rhombidodecahedron
你可以分发一个带清单的JAR文件或使用Java Web Start,但是每个都会得到一个(不同的)通用图标。 - trashgod

5

java -Xdock:icon=/path/myIcon.png myApp


只要你使用的是Mac电脑,这个功能就非常好用(不幸的是,在其他平台上它会崩溃)。 - tresf

1

我已经查看了您的错误,这与MacOS jdk有关,这在升级到10.7.4后开始出现

如果这可以帮助您,请查看this


1
一个Java 9+的解决方案:
Taskbar.getTaskbar().setIconImage(myImage);

...或者对于仍需要针对Java 8进行编译的项目...

/**
 * Use reflection to attempt to set the taskbar icon using Java 9+
 */
public void setTaskbarIcon(Image image) {
    try {
        Class taskbar = Class.forName("java.awt.Taskbar");
        Method getTaskbar = taskbar.getDeclaredMethod("getTaskbar");
        Object instance = getTaskbar.invoke(taskbar);
        Method setIconImage = instance.getClass().getDeclaredMethod("setIconImage", Image.class);
        setIconImage.invoke(instance, image);
    } catch (Throwable t) {
        t.printStackTrace();
    }
}

这仍然存在其他帖子中解释的限制(例如启动图标不正确),以及图标分辨率限制未使用多维.icns文件,但对于许多情况来说,这将比通用的Java图标更好。 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接