6

我有一个可以在 OS X 上运行的 Java 桌面应用程序。

现在新的 MacBook Pro 有一个视网膜显示屏,我很担心:它在 Swing 方面是如何工作的?

当 Java 应用程序同时使用 Swing 组件和一些位图图形(如自定义图标/ImageIcon)时会怎样?

是否应该自动调整所有桌面 Java 应用程序的大小(例如通过将每个像素翻两番)或者我是否需要创建两个版本的图标集(例如,一个具有 24x24 图标,另一个具有 96x96 图标)并以某种方式确定该应用程序在视网膜显示器上运行?

4

5 回答 5

7

使用 IconLoader 库。它支持 HiDPI 图像http://bulenkov.com/iconloader/它还提供了一种处理 HiDPI 图像(绘图等)的方法

于 2014-03-05T10:59:51.593 回答
6

在 Apple 的 Java 6 上,您可以提供同一图像的多个版本。根据屏幕(视网膜与否),选择并绘制一个或另一个图像。

但是,这些图像必须以特殊方式加载:

Toolkit.getDefaultToolkit().getImage("NSImage://your_image_name_without_extension");

例如,如果您的(常规分辨率)图像被称为:“scissor.png”,您必须创建一个高分辨率版本“scissor@2x.png”(遵循Apple 命名约定)并将两个图像放在Resources您的目录中应用程序包(是的,您需要捆绑您的应用程序)。然后调用:

Image img = Toolkit.getDefaultToolkit().getImage("NSImage://scissor");

您可以在按钮中使用生成的图像,它会神奇地以正确的分辨率绘制。

您可以使用其他两个“技巧”:

  1. 在绘制图像之前在 Graphics2D 对象上使用 (0.5, 0.5) 的 AffineTransform。另请参阅此 java-dev 消息
  2. 使用此 hack以编程方式创建图像的高 dpi 版本

第一个“技巧”(0.5 缩放)现在也适用于 Oracle 的 Java 7/8。即,如果您直接绘制一个缩放为 0.5 的图像到组件的 Graphics 对象,它将在 Retina 显示器上以高分辨率呈现(并且也是其原始大小的一半)。

更新

从 Java 9 开始,通过MultiResolutionImage接口对不同分辨率的图像提供了更好的内置支持。有关更多详细信息,请参阅此答案

于 2013-04-29T09:53:33.600 回答
3

我可以确认您的图像缩放适用于 Oracle Java 1.8。我无法让NSImage黑客在 java 1.7 或 1.8 上工作。我认为这只适用于Mac的Java 6 ...

除非其他人有更好的解决方案,否则我所做的如下:

创建两组图标。如果您有一个48pixel宽度图标,请创建一个48px@normalDPI和另一个 at 96pxwith 2x DPI。重命名2xDPI图像@2x.png以符合苹果命名标准。

子类化ImageIcon并调用它RetinaIcon或其他任何东西。您可以按如下方式测试 Retina 显示屏:

public static boolean isRetina() {

boolean isRetina = false;
GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();

try {
              Field field = graphicsDevice.getClass().getDeclaredField("scale");
        if (field != null) {
            field.setAccessible(true);
            Object scale = field.get(graphicsDevice);
            if(scale instanceof Integer && ((Integer) scale).intValue() == 2) {
                isRetina = true;
            }
        }
    } 
    catch (Exception e) {
        e.printStackTrace();
    }
    return isRetina;
}

确保@Override新类的宽度和高度ImageIcon如下:

@Override
public int getIconWidth()
{
    if(isRetina())
    {
        return super.getIconWidth()/2;
    }
    return super.getIconWidth();
}

@Override
public int getIconHeight()
{
    if(isRetina())
    {
        return super.getIconHeight()/2;
    }
    return super.getIconHeight();
}

一旦您对视网膜屏幕进行了测试并且您的自定义宽度/高度方法被覆盖,您可以painIcon按如下方式自定义该方法:

@Override
public synchronized void paintIcon(Component c, Graphics g, int x, int y) 
{
    ImageObserver observer = getImageObserver();

    if (observer == null) 
    {
        observer = c;
    }

    Image image = getImage();
    int width = image.getWidth(observer);
    int height = image.getHeight(observer);
    final Graphics2D g2d = (Graphics2D)g.create(x, y, width, height);

    if(isRetina())
    {
        g2d.scale(0.5, 0.5);
    }
    else
    {

    }
    g2d.drawImage(image, 0, 0, observer);
    g2d.scale(1, 1);
    g2d.dispose();
}

我不知道这将如何在多个屏幕上工作——还有其他人可以帮忙吗???

希望这段代码能有所帮助!

杰森·巴拉克劳。

这是使用上述缩放的示例: RetinaIcon 在左侧。ImageIcon 在右侧

于 2016-01-14T10:21:34.357 回答
1

这是一个解决方案,在苹果菜单中使用图标时也可以使用。那里的图标自动变灰。所以我实现了一个密集绘制的类 DenseIcon:

public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
    if(getImageObserver() == null) {
        g.drawImage(getImage0(), x, y, getIconWidth(), getIconHeight(), c);
    } else {
        g.drawImage(getImage0(), x, y, getIconWidth(), getIconHeight(), getImageObserver());
    }
}

如何挂钩我还没有弄清楚的变灰。因此,作为一个组合,我们返回一个低分辨率图像,以便菜单可以进行修改:

public Image getImage() {
    Image image = getImage0().getScaledInstance(
            getIconWidth(),
            getIconHeight(),
            Image.SCALE_SMOOTH);
    ImageIcon icon = new ImageIcon(image, getDescription());
    return icon.getImage();
}

您可以在gist上找到完整课程的代码。您需要使用两倍大小的图像的 URL 来实例化图标类。适用于 2K 显示器。

于 2017-05-04T17:54:42.337 回答
0

这是我的视网膜 macbook '12 上图标的样子:

在此处输入图像描述

在 IntelliJ IDEA 11(swing 应用程序)的左侧图标和声称是retinized的 IDEA 12 右侧。如您所见,自动调整大小的图标(在左侧)看起来很丑。

据我所知,他们和 Chrome 团队的人一样,是通过提供双倍大小的图标来实现的。

于 2012-12-26T01:19:51.963 回答