跳到主要内容

JEP 263:Windows 和 Linux 上的 HiDPI 图形

QWen Max 中英对照

概述

在 Windows 和 Linux 上实现 HiDPI 图形。

动机

开发者和用户对于运行在 HiDPI 显示器上的应用程序有一些基本的期望:

  • 窗口和 GUI 组件应根据平台建议具有适当的大小,

  • 文本应保持清晰,尽管 HiDPI 设置指定了任何默认缩放比例,而且

  • 图标和图像应平滑,并且最好具有适合显示器像素密度的细节。

不幸的是,即使在像素密度是传统显示器 2 到 3 倍的 HiDPI 显示器上,Windows 和 Linux 上的 Java 应用程序仍然基于像素进行尺寸调整和渲染。这导致 GUI 组件和窗口的大小比正常情况下小 2 到 3 倍,因此太小而无法阅读或有效交互。

JDK 已经在 Mac OS X 上支持 HiDPI “视网膜显示屏”,并根据显示器的密度以适当的尺寸显示清晰的文字和图像。Mac “视网膜”支持已经为在所有平台上支持 HiDPI 显示器提供了相当多的基础工作,但各平台中应用程序应如何处理 HiDPI 的方式差异意味着仍需额外的工作来将针对 Mac 的实现推广至其他平台。

现在应该为 Windows 和 Linux 平台提供相同的自动缩放和调整大小功能。

描述

Windows 上的 HiDPI

Windows 控制面板在多个版本中为用户提供了一些请求缩放桌面组件和窗口的方式(自 Windows XP 以来以各种形式存在)。某些操作系统版本还提供了自动缩放未声明为“DPI 感知”的应用程序的功能。默认情况下,“非 DPI 感知”应用程序的缩放可能会导致许多视觉问题,包括模糊的窗口、不准确的布局以及被裁剪的文本。因此,Java 运行时一段时间以来已声明自己为“DPI 感知”,以避免模糊和布局问题。然而,根据 DPI 缩放内容的支持并非易事,而且由于大多数显示密度仅需要 25% 的小幅度缩放,因此决定忽略推荐的缩放指南和策略,继续以 1:1 的像素比例渲染 AWT 和 Swing 组件,从而使 JDK 应用程序比正常情况稍小一些,但保持了清晰的文字和图形。

然而,最近显示器在像素密度上有了很大的提升,现在很容易找到屏幕密度是当初制定这些决策时常见显示器 2 到 3 倍的笔记本电脑。因此,在这些较新的 Windows 机器上,Java 应用程序有时会小到无法使用 —— 这已经不再是“稍微小一点与模糊窗口”的问题了,所以我们需要正确地缩放我们的应用程序窗口。

Windows API 提供了度量、机制和指南,用于编写 DPI 感知应用程序,以使 UI 在各种 DPI 显示设置中保持一致的外观,并响应用户对于使 UI 足够大以便用户能够舒适地与 UI 组件交互的偏好。

Windows 的 Direct2D 图形 API 会自动遵循系统 DPI,使用 DIP(设备无关像素)表示坐标,允许位图具有 DPI,并通过考虑 DPI 正确缩放它们。然而,AWT 和 Swing 库并非基于 Direct2D 图形 API。

Windows 7 及之后的版本提供了多种方法来获取桌面的水平和垂直 DPI,包括 GetDesktopDpi 方法,以及在 Windows 8.1 中新增的 GetDpiForMonitor 方法和 WM_DPICHANGED 消息。这些值可以用于缩放窗口大小、鼠标坐标和字体,以支持 AWT/Swing 库中的 HiDPI 功能。Java2D 渲染层中已经具备了必要的缩放支持,但我们需要将这些值传递给 Swing 和 AWT,并更新它们的组件以识别并遵循缩放因子。这种支持包括确保将所需的渲染缩放因子提供给 Java2D 的 Graphics 对象,中间渲染图像按照目标的适当缩放因子进行渲染,并且需要重新检查渲染调用中关于坐标如何映射到像素的假设。

Linux 上的 HiDPI

已在 GTK+ 3 库中实现了 HiDPI 支持。当使用 HiDPI 显示器时,GTK 库会自动在客户端缩放应用程序。

Java2D 和 AWT 使用 XLib 库,该库不支持 HiDPI。因此,在 Linux 的 HiDPI 显示器上,当前的 Java 应用程序可能会显得比正常大小小 2 到 3 倍。

此外,任何使用 GTK 外观风格的 Java 应用程序可能会自动从 GTK 库中受益于 HiDPI 支持,而窗口和其他组件的大小可能与为满足 HiDPI 要求而放大 2-3 倍的 GTK 组件相匹配。这可能会导致诸如 JDK-8058742 中描述的问题。

替代方案

开发者可以手动缩放应用程序在高分辨率显示器上运行时的所有 GUI 元素,但这需要对应用程序进行大量的重构工作,并且 Swing 和 AWT 组件并不是为了很好地配合外部的缩放尝试而编写的。

测试

以下测试应在 HiDPI 显示器上进行。屏幕缩放比例多样化会更好 —— 192 DPI 和 144 DPI 将是一个不错的最小支持矩阵。请注意,通过 Windows 控制面板可以将非常高 DPI 的显示器设置为较低的人工 DPI,因此不一定需要额外的系统,但必须在测试运行之间重新配置。此外,在 Windows 上更改 DPI 通常需要重启才能使新的 DPI 生效并通知到应用程序。

在 Windows 中,可以在控制面板中设置 DPI。Windows 7、Windows 8.1 和更早版本的 Windows 上存在不同版本的控制面板和允许的设置,但所有这些设置都会向应用程序传递相同类型的信息(X 和 Y 的 DPI 指示值),因此目前不需要对控制面板的不同版本进行额外测试,这只是影响测试环境配置的一个细节。

在 Linux 上,可以使用 GDK_SCALE 环境变量来为 GTK+ 3 模拟 DPI 设置,或者使用 GNOME 3 的 scaling-factor 设置。

应检查以下项目:

  • 文本不应模糊
  • 组件中的文本(标签和按钮)不应被裁剪
  • UI 组件布局在 AWT/Swing 上应保持合理(即没有重叠或奇怪的间隙)
  • 在 AWT/Swing 对话框和组件上,当应用程序或测试用例提供时,应使用高分辨率图标
  • 应用程序应正确处理鼠标事件
  • 应用程序的尺寸应与 DPI 感知的原生应用程序相似