如何在Java中检测用户是否拥有Retina显示屏?我已经知道使用Toolkit.getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor")
来检测比例因子,但是Java不允许我将返回的值转换为int类型。我想知道如何将其转换为int类型,或者另一种检测Retina显示屏的方法。
如何在Java中检测用户是否拥有Retina显示屏?我已经知道使用Toolkit.getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor")
来检测比例因子,但是Java不允许我将返回的值转换为int类型。我想知道如何将其转换为int类型,或者另一种检测Retina显示屏的方法。
请注意,用户可能拥有多个显示器!在这种情况下,“检测Retina显示屏”是什么意思?
对于大多数情况,您需要将图像呈现在GUI组件上。因此,您需要检测组件所在的显示器。
幸运的是,java.awt.Component
具有一个getGraphicsConfiguration
方法,可以提供我们必要的信息。
然而,Java 8(和7)和Java 9需要不同的处理方式:Java 9直接通过图形设备的默认转换公开所需的信息。 Java 7和8也公开这个转换,但它始终设置为身份转换(即没有转换),即使是Retina显示屏也是如此。
对于Java < 9,我们需要使用反射来查询OpenJDK类中实现Mac图形的特定字段。
以下类实现了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();
}
}
实际上,将对话框从一个屏幕移动到另一个屏幕会导致组件重新渲染。如果组件的渲染代码使用上述类来查找正确的分辨率,则无论它们当前位于哪个显示器上,它们都将正确地呈现。
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;
}
对于Java 9,也可以这样实现:
public static boolean isMacRetinaDisplay() {
final GraphicsConfiguration gfxConfig = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
final AffineTransform transform = gfxConfig.getDefaultTransform();
return !transform.isIdentity();
}