You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rad Studio 12.1中FireMonkey项目Screen->Displays返回错误屏幕尺寸

问题原因与解决方案

核心原因:FireMonkey高DPI处理逻辑变更

从RAD Studio 10.3到12.1,FireMonkey的高DPI缩放感知与像素值返回逻辑发生了调整。你的主屏幕(3840×2400)是高DPI屏幕(缩放比例200%),12.1中默认情况下Screen->Displays返回的是缩放后逻辑像素,而非物理像素——1536×960正是3840×2400除以2的结果。同时,屏幕位置偏移问题也源于DPI缩放后的坐标映射错误。

10.3版本中FireMonkey对高DPI的处理更依赖系统全局缩放,直接返回物理像素;而12.1默认启用了每监视器DPI感知(Per-Monitor DPI Awareness v2),但FireMonkey的Screen组件在某些场景下未正确转换物理像素与逻辑像素的对应关系,导致尺寸和位置偏差。

解决步骤

1. 调整项目DPI设置

打开RAD Studio 12.1的项目选项:

  • 导航到Application > Manifest,确保Per-Monitor DPI Awareness设置为PerMonitorV2(或根据需求调整)。
  • 切换到Application > Appearance,确认Scaling选项中的High DPI Mode设置为System或Per Monitor,避免强制缩放逻辑像素。

2. 手动转换物理像素与逻辑像素

如果项目需要保留当前DPI设置,可通过FireMonkey的DPI转换方法获取物理像素:

Screen->UpdateDisplayInformation();
for (int i = 0; i < Screen->DisplayCount; i++)
{
    // 获取当前屏幕的DPI缩放比例
    float dpiScale = Screen->Displays[i].DPIScaling;
    // 转换为物理像素
    int physicalWidth = static_cast<int>(Screen->Displays[i].Bounds.Width() * dpiScale);
    int physicalHeight = static_cast<int>(Screen->Displays[i].Bounds.Height() * dpiScale);
    // 获取物理位置(Left/Top同样需乘以dpiScale)
    int physicalLeft = static_cast<int>(Screen->Displays[i].Bounds.Left * dpiScale);
    
    MainForm->LogMsg("Screen : " + IntToStr(i + 1) + 
                     ", 物理尺寸: " + IntToStr(physicalWidth) + "×" + IntToStr(physicalHeight) +
                     ", 物理位置Left: " + IntToStr(physicalLeft));
}

3. 绕过FireMonkey封装,调用Windows原生API

如果上述方法仍无法解决,直接使用Windows原生API获取准确的屏幕信息,不受FireMonkey逻辑影响:

#include <Windows.h>

// 回调函数用于枚举显示器
BOOL CALLBACK EnumMonitorsProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    std::vector<RECT>* pMonitorRects = reinterpret_cast<std::vector<RECT>*>(dwData);
    pMonitorRects->push_back(*lprcMonitor);
    return TRUE;
}

// 获取所有物理屏幕的尺寸与位置
void GetPhysicalDisplays(std::vector<RECT>& outMonitorRects)
{
    outMonitorRects.clear();
    EnumDisplayMonitors(NULL, NULL, EnumMonitorsProc, reinterpret_cast<LPARAM>(&outMonitorRects));
}

// 使用示例
std::vector<RECT> monitorRects;
GetPhysicalDisplays(monitorRects);
for (size_t i = 0; i < monitorRects.size(); i++)
{
    RECT rc = monitorRects[i];
    int width = rc.right - rc.left;
    int height = rc.bottom - rc.top;
    MainForm->LogMsg("Screen : " + IntToStr(i + 1) + "," + 
                     IntToStr(width) + "," + IntToStr(height) +
                     ", Left: " + IntToStr(rc.left));
}

4. 验证屏幕索引顺序

12.1中Screen->Displays的索引顺序可能与10.3不同,建议同时打印屏幕的DeviceName或Primary属性,确认索引对应的实际屏幕:

MainForm->LogMsg("Screen : " + IntToStr(i + 1) + 
                 ", IsPrimary: " + BoolToStr(Screen->Displays[i].Primary) +
                 ", DeviceName: " + Screen->Displays[i].DeviceName);

内容的提问来源于stack exchange,提问作者Barry Andrews

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:42:33