【问题标题】:How do you detect a Retina Display in Java?如何在 Java 中检测 Retina Display?
【发布时间】:2013-12-24 23:22:06
【问题描述】:

如何在 Java 中检测用户是否有视网膜显示器?我已经知道使用Toolkit.getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor") 检测比例因子,但是java 不允许我将返回的值转换为int。我想知道如何将其转换为 int 或其他检测视网膜显示的方式。

【问题讨论】:

  • 如何在配备 Retina 显示屏的设备上运行 Java?或者我的意思是,你正在运行哪个 Java...
  • 你在用什么不能让你将返回的值转换为int? (它应该是一个浮点数)。
  • 我在配备 Retina 显示屏的 Macbook Pro 上运行它。当我运行代码并尝试将返回的值类型转换为 Integer 时,它给了我一个错误提示 Exception in thread "main" java.lang.ClassCastException: java.lang.Float cannot be cast to java.lang.Integer
  • 不要那样做!只需使用intValue()...
  • Java 不允许我这样做,因为“方法 intValue() 没有为 Object 类型定义。”

标签: java retina-display


【解决方案1】:

我会以这种方式获得价值 -

public static boolean hasRetinaDisplay() {
  Object obj = Toolkit.getDefaultToolkit()
      .getDesktopProperty(
          "apple.awt.contentScaleFactor");
  if (obj instanceof Float) {
    Float f = (Float) obj;
    int scale = f.intValue();
    return (scale == 2); // 1 indicates a regular mac display.
  }
  return false;
}

【讨论】:

  • 非常感谢,这行得通。我想我只需要 if 语句并将其转换为浮点数,然后再将其转换为 int。
  • 请问您使用视网膜显示器可以获得什么价值?我将改写一个完整实用方法的答案...
  • 如果是 Retina 显示器,则为 2,如果不是并且计算机是 mac,则为 1,否则为 null。
  • 如果有一些适用于 Oracle JDK 的东西会很好,因为新的 JDK 现在支持视网膜显示。
  • 在最新的 Oracle JDK 上对我不起作用,obj 只是空值,但是我找到了另一种获取该信息的方法,并写了this answer
【解决方案2】:

注意用户可能有多个显示器!在这种情况下,“检测到 Retina 显示器”是什么意思?

在大多数情况下,您都对将图像渲染到 GUI 组件上感兴趣。因此,您需要检测组件在哪个显示器上

幸运的是java.awt.Component 有一个getGraphicsConfiguration method 可以为我们提供必要的信息。

但是,Java 8(和 7)和 Java 9 需要不同的处理方式:Java 9 直接通过 graphics device’s default transform 公开必要的信息。 Java 7 和 8 也公开了这种转换,但它始终设置为恒等转换(即无转换),即使对于 Retina 显示器也是如此。

对于Java

以下类实现了对 Retina 显示器的必要检查,并适用于 Java 8 和 Java 9。Java 7 可能也适用于一些琐碎的更改,但我没有对其进行测试。

package me.klmr.ui;

import java.awt.*;
import java.lang.reflect.Method;

public final class Device {
    private enum JavaVersion {
        V8,
        V9
    }

    private static final JavaVersion JAVA_VERSION = getJavaVersion();

    private static JavaVersion getJavaVersion() {
        final String versionString = System.getProperty("java.version");
        if (versionString.startsWith("1.8")) return JavaVersion.V8;
        if (versionString.startsWith("9.")) return JavaVersion.V9;
        throw new RuntimeException("Unsupported Java version");
    }

    public static GraphicsConfiguration getCurrentConfiguration(final Component component) {
        final GraphicsConfiguration graphicsConfiguration = component.getGraphicsConfiguration();
        if (graphicsConfiguration == null) {
            return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        } else {
            return graphicsConfiguration;
        }
    }

    public static GraphicsDevice getCurrentDevice(final Component component) {
        final GraphicsConfiguration graphicsConfiguration = component.getGraphicsConfiguration();
        if (graphicsConfiguration == null) {
            return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        } else {
            return graphicsConfiguration.getDevice();
        }
    }

    public static boolean isOnRetinaDisplay(final Component component) {
        switch (JAVA_VERSION) {
            case V8: return isOnRetinaDisplayJava8(component);
            case V9: return isOnRetinaDisplayJava9(component);
            default: throw new AssertionError("Unreachable");
        }
    }

    public static double getDisplayScalingFactor(final Component component) {
        switch (JAVA_VERSION) {
            case V8: return getDisplayScalingFactorJava8(component);
            case V9: return getDisplayScalingFactorJava9(component);
            default: throw new AssertionError("Unreachable");
        }
    }

    private static boolean isOnRetinaDisplayJava8(final Component component) {
        final GraphicsDevice device = getCurrentDevice(component);
        try {
            final Method getScaleFactorMethod = device.getClass().getMethod("getScaleFactor");
            final Object scale = getScaleFactorMethod.invoke(device);
            return scale instanceof Integer && ((Integer) scale).intValue() == 2;
        } catch (ReflectiveOperationException e) {
            return false;
        }
    }

    private static boolean isOnRetinaDisplayJava9(final Component component) {
        return ! getCurrentConfiguration(component).getDefaultTransform().isIdentity();
    }

    private static double getDisplayScalingFactorJava8(final Component component) {
        return isOnRetinaDisplayJava8(component) ? 2.0 : 1.0;
    }

    private static double getDisplayScalingFactorJava9(final Component component) {
        return getCurrentConfiguration(component).getDefaultTransform().getScaleX();
    }
}

实际上,将对话框从一个屏幕移动到另一个屏幕会导致组件重新渲染。如果组件的渲染代码使用上面的类来找出正确的分辨率,那么无论它们当前在哪个显示器上,它们都会正确渲染。

【讨论】:

    【解决方案3】:

    对于 Java 9,这也适用:

        public static boolean isMacRetinaDisplay() {
            final GraphicsConfiguration gfxConfig = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
            final AffineTransform transform = gfxConfig.getDefaultTransform();
            return !transform.isIdentity();
        }
    

    您也可以检查变换的比例因子并检查它是否等于 2,否则回退到非视网膜。

    【讨论】:

    • 是什么让这个 Java 9 变得特别?在 Java 7 中编译(还没有运行它,没有愚蠢的 Retina Mac)。
    • @NateS API 存在,但在 Java 9 之前它返回错误的值:Java 7 和 Java 8 即使在 Retina 显示器上也使用身份转换,ScaleXScaleY 值总是1.0,不管实际的硬件显示比例值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-06
    相关资源
    最近更新 更多