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

为何TDisplay.Index与Windows索引不一致?如何获取系统一致显示顺序

获取与系统设置一致的显示器索引(Delphi跨平台方案)

Delphi默认的Screen.Displays数组按屏幕虚拟坐标(从左到右、从上到下)排序,和Windows/Mac系统设置里的显示器编号顺序不一致。以下是分平台的解决方案:

Windows平台实现

Windows系统的显示器编号顺序由显示配置的活动路径决定,需通过QueryDisplayConfig API获取系统原生排序,再映射到Delphi的TMonitor对象:

示例代码

uses
  Winapi.Windows, Winapi.DisplayConfig, Winapi.Monitors, System.Types;

function GetWindowsSystemOrderedDisplays: TArray<TMonitor>;
var
  PathCount, ModeCount: UINT;
  Paths: PDISPLAYCONFIG_PATH_INFO;
  Modes: PDISPLAYCONFIG_MODE_INFO;
  i: Integer;
  Monitor: TMonitor;
  DisplayDevice: TDisplayDevice;
begin
  Result := [];
  // 获取配置缓冲区大小
  if GetDisplayConfigBufferSizes(QDC_ALL_PATHS, @PathCount, @ModeCount) <> ERROR_SUCCESS then
    Exit;

  GetMem(Paths, PathCount * SizeOf(DISPLAYCONFIG_PATH_INFO));
  GetMem(Modes, ModeCount * SizeOf(DISPLAYCONFIG_MODE_INFO));
  try
    if QueryDisplayConfig(QDC_ALL_PATHS, @PathCount, Paths, @ModeCount, Modes, nil) <> ERROR_SUCCESS then
      Exit;

    for i := 0 to PathCount - 1 do
    begin
      // 仅处理活动的显示器路径
      if (Paths[i].flags and DISPLAYCONFIG_PATH_ACTIVE) = 0 then
        Continue;

      // 通过设备ID枚举显示器设备
      FillChar(DisplayDevice, SizeOf(DisplayDevice), 0);
      DisplayDevice.cb := SizeOf(DisplayDevice);
      if EnumDisplayDevices(PChar(Paths[i].targetInfo.adapterId), Paths[i].targetInfo.id, DisplayDevice, 0) then
      begin
        // 匹配Delphi的TMonitor对象
        for Monitor in Screen.Monitors do
        begin
          if Monitor.DeviceName = DisplayDevice.DeviceName then
          begin
            Result := Result + [Monitor];
            Break;
          end;
        end;
      end;
    end;
  finally
    FreeMem(Paths);
    FreeMem(Modes);
  end;
end;

说明

  • 返回数组顺序与Windows设置中显示器编号完全一致(索引0对应系统里的「显示器1」,索引1对应「显示器2」)。
  • 自动过滤非活动显示器路径,只返回当前正在使用的显示器。

MacOS平台实现

Mac系统中,Cocoa框架的NSScreen.screens方法返回的屏幕顺序就是系统偏好设置里的显示器列表顺序,通过匹配屏幕边界可映射到Delphi的TMonitor:

示例代码

uses
  Macapi.AppKit, Macapi.Foundation, System.Types;

function GetMacSystemOrderedDisplays: TArray<TMonitor>;
var
  NScreens: NSArray;
  i: Integer;
  NSScr: NSScreen;
  Monitor: TMonitor;
  ScreenRect: CGRect;
begin
  Result := [];
  NScreens := TNSScreen.Wrap(TNSScreen.OCClass.screens);
  for i := 0 to NScreens.count - 1 do
  begin
    NSScr := TNSScreen.Wrap(NScreens.objectAtIndex(i));
    ScreenRect := NSScr.frame;
    // 通过屏幕边界匹配Delphi的TMonitor
    for Monitor in Screen.Monitors do
    begin
      if (Monitor.Bounds.Left = Round(ScreenRect.origin.x)) and
         (Monitor.Bounds.Top = Round(ScreenRect.origin.y)) and
         (Monitor.Bounds.Width = Round(ScreenRect.size.width)) and
         (Monitor.Bounds.Height = Round(ScreenRect.size.height)) then
      begin
        Result := Result + [Monitor];
        Break;
      end;
    end;
  end;
end;

说明

  • NSScreen.screens的顺序与Mac系统偏好设置中「显示器」面板的列表顺序完全一致。
  • 若存在分辨率缩放,直接取整匹配即可适配常规场景。

跨平台统一调用

通过条件编译封装统一函数,自动适配不同平台:

function GetSystemOrderedDisplays: TArray<TMonitor>;
begin
{$IFDEF MSWINDOWS}
  Result := GetWindowsSystemOrderedDisplays;
{$ENDIF}
{$IFDEF MACOS}
  Result := GetMacSystemOrderedDisplays;
{$ENDIF}
end;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 18:51:19