simpread Understanding Screen Scaling Issues
本文由 简悦 SimpRead 转码, 原文地址 learn.microsoft.com
Windows Vista and later versions of the operating system enable users to change the dots per inch (dp……
Windows Vista and later versions of the operating system enable users to change the dots per inch (dpi) setting so that most UI elements on the screen appear larger. In earlier versions of Windows, the scaling had to be implemented by applications. In Windows Vista and later, the Desktop Window Manager (DWM) performs default scaling for all applications that do not handle their own scaling. Microsoft UI Automation client applications must take this feature into account.
Windows Vista 及更高版本的操作系统允许用户更改每英寸点数 (dpi) 设置,以便屏幕上的大多数 UI 元素显示得更大。在早期版本的 Windows 中,缩放必须由应用程序实现。在 Windows Vista 及更高版本中,桌面窗口管理器 (DWM) 会为所有不处理自身缩放的应用程序执行默认缩放。Microsoft UI 自动化客户端应用程序必须考虑此功能。
This topic contains the following sections:
本主题包含以下部分:
- Scaling in Windows Vista and Later
在 Windows Vista 及更高版本中缩放 - Scaling in UI Automation Clients
UI 自动化客户端的扩展
Scaling in Windows Vista and Later
在 Windows Vista 及更高版本中缩放
The default dpi setting is 96, which means that 96 pixels occupy a width or height of one notional inch. The exact measure of an “inch” depends on the size and physical resolution of the monitor. For example, on a monitor 12 inches wide, at a horizontal resolution of 1280 pixels, a horizontal line of 96 pixels extends about 9/10 of an inch.
默认 dpi 设置为 96,这意味着 96 个像素占据 1 英寸的宽度或高度。“英寸” 的具体长度取决于显示器的尺寸和物理分辨率。例如,在 12 英寸宽的显示器上,水平分辨率为 1280 像素,一条 96 像素的水平线延伸约 9/10 英寸。
Changing the dpi setting is not the same as changing the screen resolution. With dpi scaling, the number of physical pixels on the screen remains the same. However, scaling is applied to the size and location of UI elements. This scaling can be performed automatically by the DWM for the desktop and for applications that do not explicitly ask not to be scaled.
更改 dpi 设置与更改屏幕分辨率不同。使用 dpi 缩放时,屏幕上的物理像素数量保持不变。但是,缩放会应用于 UI 元素的大小和位置。对于桌面应用以及未明确要求不缩放的应用程序,DWM 可以自动执行此缩放。
In effect, when the user sets the scale factor to 120 dpi, a vertical or horizontal inch on the screen becomes bigger by 25 percent. All dimensions are scaled accordingly. The offset of an application window from the top edge and left edge of the screen increases by 25 percent. If application scaling is enabled and the application is not dpi-aware, the size of the window increases in the same proportion, along with the offsets and sizes of all UI elements it contains.
实际上,当用户将缩放比例设置为 120 dpi 时,屏幕上垂直或水平方向的 1 英寸会放大 25%。所有尺寸都会相应缩放。应用程序窗口与屏幕上边缘和左边缘的偏移量会增加 25%。如果启用了应用程序缩放功能,并且应用程序不支持 dpi 缩放,则窗口的大小会按相同比例增大,其中包含的所有 UI 元素的偏移量和大小也会随之增大。
Note 笔记
By default, the DWM does not perform scaling for non-dpi-aware applications when the user sets the dpi to 120, but does perform scaling when the dpi is set to a custom value of 144 or higher. However, the user can override the default behavior.
默认情况下,当用户将 dpi 设置为 120 时,DWM 不会对不支持 dpi 的应用程序执行缩放操作;但当 dpi 设置为自定义值 144 或更高时,DWM 会执行缩放操作。不过,用户可以覆盖默认行为。
Screen scaling creates new challenges for applications that are concerned in any way with screen coordinates. The screen now contains two coordinate systems: physical and logical. The physical coordinates of a point are the actual offset in pixels from the upper-left of the origin point. The logical coordinates are the offsets as they would be if the pixels themselves were scaled.
屏幕缩放给与屏幕坐标相关的应用程序带来了新的挑战。屏幕现在包含两个坐标系:物理坐标系和逻辑坐标系。一个点的物理坐标是相对于原点左上角的实际偏移量(以像素为单位)。逻辑坐标是像素本身缩放后的偏移量。
Suppose you design a dialog box with a button at coordinates (100, 48). When this dialog box is displayed at the default 96 dpi, the button is located at physical coordinates of (100, 48). At 120 dpi, it is located at physical coordinates of (125, 60). But the logical coordinates are the same at any dpi setting: (100, 48).
假设你设计了一个对话框,其中按钮的坐标为 (100, 48)。当此对话框以默认的 96 dpi 显示时,该按钮的物理坐标为 (100, 48)。在 120 dpi 下,它的物理坐标为 (125, 60)。但无论哪种 dpi 设置,其逻辑坐标都是相同的:(100, 48)。
Logical coordinates are important, because they make the behavior of the operating system and applications consistent, regardless of the dpi setting. For example, typically, the GetCursorPos function returns the logical coordinates. If you move the cursor over an element in a dialog box, the same coordinates are returned, regardless of the dpi setting. If you draw a control at (100, 100), it is drawn to those logical coordinates, and will occupy the same relative position at any dpi setting.
逻辑坐标非常重要,因为它们使操作系统和应用程序的行为保持一致,而不受 dpi 设置的影响。例如,通常情况下, GetCursorPos 函数会返回逻辑坐标。如果将光标移动到对话框中的某个元素上,无论 dpi 设置如何,都会返回相同的坐标。如果在 (100, 100) 处绘制一个控件,它将被绘制到这些逻辑坐标上,并且在任何 dpi 设置下都将占据相同的相对位置。
Scaling in UI Automation Clients
UI 自动化客户端的扩展
The UI Automation API does not use logical coordinates. The following methods and properties return physical coordinates or take physical coordinates as parameters.
UI 自动化 API 不使用逻辑坐标。以下方法和属性返回物理坐标或将物理坐标作为参数。
- IUIAutomation::ElementFromPoint
- IUIAutomation::ElementFromPointBuildCache
- IUIAutomationElement::GetClickablePoint
- IUIAutomationElement::CurrentBoundingRectangle
- IUIAutomationElement::CachedBoundingRectangle
- IRawElementProviderFragment::BoundingRectangle
By default, UI Automation applications that are running in an environment that is not set to 96 dpi will not obtain correct results from these methods and properties. For example, because the cursor position is in logical coordinates, the client cannot pass these coordinates to IUIAutomation::ElementFromPoint to obtain the element that is under the cursor. In addition, the application will not be able to correctly place windows outside its client area.
默认情况下,在未设置为 96 dpi 的环境中运行的 UI 自动化应用程序将无法从这些方法和属性获取正确的结果。例如,由于光标位置采用逻辑坐标,因此客户端无法将这些坐标传递给 IUIAutomation::ElementFromPoint 以获取光标下的元素。此外,应用程序将无法正确地将窗口放置在其客户端区域之外。
The solution has two parts.
解决方案分为两部分。
First, make the client application dpi-aware. To do this, call the SetProcessDPIAware function at startup. This function makes the entire process dpi-aware, meaning that all windows that belong to the process are unscaled.
首先,让客户端应用程序支持 DPI 感知。为此,请在启动时调用 SetProcessDPIAware 函数。此函数使整个进程支持 DPI 感知,这意味着属于该进程的所有窗口均不缩放。
Second, to get cursor coordinates, call the GetPhysicalCursorPos function.
其次,要获取光标坐标,调用 GetPhysicalCursorPos 函数。