【问题标题】:Different wallpaper for each monitor in a multi-monitor setup in Windows 10Windows 10 中的多显示器设置中的每台显示器的不同壁纸
【发布时间】:2019-11-18 13:14:44
【问题描述】:

有很多关于在 Windows 中以编程方式在多显示器设置上设置壁纸的问题和答案,但我专门针对 Windows 10(可能还有 Windows 8)询问,因为它的工作方式似乎与我发现的所有解释不同.

Raymond Chen 有一篇文章“如何在每台显示器上放置不同的壁纸?” (https://devblogs.microsoft.com/oldnewthing/?p=25003),也在Monitors position on Windows wallpaper 中引用。核心概念是 Windows 将提供的位图的左上角放在主显示器的左上角,并环绕以填充左侧和/或上方的任何桌面空间。我明白这一点,我使用这些知识编写了一个小程序,它在 Windows 7 中运行良好。

它是如何工作的:我创建了一个位图,它在概念上涵盖了用户所看到的整个桌面空间。我将每个监视器的内容绘制到该位图的适当位置(程序是使用 VCL 用 C++ 编写的,但在其他编程环境中原理保持不变):

TRect GetMonitorRect_WallpaperCoords(int MonitorNum)
{
  Forms::TMonitor *PrimaryMonitor = Screen->Monitors[0];
  Forms::TMonitor *Monitor = Screen->Monitors[MonitorNum];
  // Get the rectangle in desktop coordinates
  TRect Rect(Monitor->Left, Monitor->Top, Monitor->Left + Monitor->Width, Monitor->Top + Monitor->Height);
  // Convert to wallpaper coordinates
  Rect.Left += PrimaryMonitor->Left - Screen->DesktopLeft;
  Rect.Top += PrimaryMonitor->Top - Screen->DesktopTop;
  Rect.Right += PrimaryMonitor->Left - Screen->DesktopLeft;
  Rect.Bottom += PrimaryMonitor->Top - Screen->DesktopTop;
  return Rect;
}

std::unique_ptr<Graphics::TBitmap> CreateWallpaperBitmap_WallpaperCoords()
{
  std::unique_ptr<Graphics::TBitmap> Bmp(new Graphics::TBitmap);
  Bmp->PixelFormat = pf24bit;
  Bmp->Width = Screen->DesktopWidth;
  Bmp->Height = Screen->DesktopHeight;

  // Draw background (not that we really need it: it will never be visible)
  Bmp->Canvas->Brush->Style = bsSolid;
  Bmp->Canvas->Brush->Color = clBlack;
  Bmp->Canvas->FillRect(TRect(0, 0, Bmp->Width, Bmp->Height));

  for (int MonitorNum = 0; MonitorNum < Screen->MonitorCount; ++MonitorNum)
    {
    TDrawContext DC(Bmp->Canvas, GetMonitorRect_WallpaperCoords(MonitorNum));
    DrawMonitor(DC);
    }

  return Bmp;
}

(绘制上下文使用坐标转换 rect 以便代码 int DrawMonitor 函数可以在像 (0, 0, 1920, 1080) 这样的矩形中绘制,而不必怀疑它在完整位图中绘制的位置,并且具有剪辑矩形,这样 DrawMonitor 就不会意外地在它正在绘制的监视器之外绘制)。

然后我将该位图转换为在放置在主显示器左上角时可以正确环绕的图像(正如 Raymond Chen 在他的文章中所描述的那样):

std::unique_ptr<Graphics::TBitmap> ConvertWallpaperToDesktopCoords(std::unique_ptr<Graphics::TBitmap> &Bmp_WallpaperCoords)
{
  std::unique_ptr<Graphics::TBitmap> Bmp_DesktopCoords(new Graphics::TBitmap);
  Bmp_DesktopCoords->PixelFormat = Bmp_WallpaperCoords->PixelFormat;
  Bmp_DesktopCoords->Width = Bmp_WallpaperCoords->Width;
  Bmp_DesktopCoords->Height = Bmp_WallpaperCoords->Height;

  // Draw Bmp_WallpaperCoords to Bmp_DesktopCoords at four different places to account for all
  // possible ways Windows wraps the wallpaper around the left and bottom edges of the desktop
  // space
  Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft, Screen->DesktopTop, Bmp_WallpaperCoords.get());
  Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft + Screen->DesktopWidth, Screen->DesktopTop, Bmp_WallpaperCoords.get());
  Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft, Screen->DesktopTop + Screen->DesktopHeight, Bmp_WallpaperCoords.get());
  Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft + Screen->DesktopWidth, Screen->DesktopTop + Screen->DesktopHeight, Bmp_WallpaperCoords.get());

  return Bmp_DesktopCoords;
}

然后我通过在注册表中写入适当的值并使用 SPI_SETDESKWALLPAPER 调用 SystemParametersInfo 来将该位图安装为墙纸:

void InstallWallpaper(const String &Fn)
{
  // Install wallpaper:
  // There are 3 name/data pairs that have an effect on the desktop wallpaper, all under HKCU\Control Panel\Desktop:
  //  - Wallpaper (REG_SZ): file path and name of wallpaper
  //  - WallpaperStyle (REG_SZ):
  //    . 0: Centered
  //    . 1: Tiled
  //    . 2: Stretched
  //  - TileWallpaper (REG_SZ):
  //    . 0: Don't tile
  //    . 1: Tile
  //  We don't use the Wallpaper value itself; instead we use SystemParametersInfo to set the wallpaper.

  // The file name needs to be absolute!
  assert(Ioutils::TPath::IsPathRooted(Fn));

  std::unique_ptr<TRegistry> Reg(new TRegistry);
  Reg->RootKey = HKEY_CURRENT_USER;
  if (Reg->OpenKey(L"Control Panel\\Desktop", false))
    {
    Reg->WriteString(L"WallpaperStyle", L"1");
    Reg->WriteString(L"TileWallpaper", L"1");
    Reg->CloseKey();
    }
  SystemParametersInfoW(SPI_SETDESKWALLPAPER, 1, Fn.c_str(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
}

但是当我在 Windows 10 中测试它时,它不再正常工作了:Windows 10 将壁纸完全放在了错误的位置。看到过去有人问过关于多显示器壁纸的问题,我希望有人在 Windows 10 上体验过。

【问题讨论】:

  • 你的问题与编程无关
  • Is This On Topic? 甚至没有接近。
  • 恐怕我说得不够清楚,但这是关于如何以编程方式设置壁纸。这非常关乎编程。
  • 在这种情况下,您有任何可以包含的相关代码吗?
  • @auburg:包含代码

标签: windows-10 vcl multiple-monitors wallpaper


【解决方案1】:

据我所知,Windows 10 将提供的位图的左上角放置在桌面空间的左上角(我指的是所有显示器的边界矩形),而不是顶部主显示器的左角。在代码中,这意味着:我省略了 ConvertWallpaperToDesktopCoords 步骤,然后它就可以正常工作了。

但是我找不到任何关于此的文档,所以我不知道这是否是对 Windows 10 是如何做到这一点的正式解释。小心使用。我也不知道这种不同的行为是从什么时候开始的:在 Windows 10 中,或者可能在 Windows 8 更早的版本中。

【讨论】:

    猜你喜欢
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多