8

我正在尝试确定如何检测用户何时将 Windows 字体大小从普通字体更改为特大字体,通过在 Windows XP 机器上执行以下步骤来选择字体大小:

  1. 右键单击桌面并选择属性。
  2. 单击外观选项卡。
  3. 选择字体大小:普通/大字体/超大字体

我的理解是字体大小的变化会导致 DPI 的变化,所以这是我到目前为止所尝试的。


我的目标:

我想检测Windows 字体大小何时从普通字体更改为大字体或超大字体,并根据该字体大小更改采取一些措施。我假设当 Windows Font Size 改变时,DPI 也会改变(尤其是当大小是 Extra Large Fonts


到目前为止我已经尝试过:

我收到了几条消息,包括:WM_SETTINGCHANGE、WM_NCCALCSIZE、WM_NCPAINT 等……但是这些消息都不是字体大小更改时所特有的,换句话说,当我收到 WM_SETTINGSCHANGE 消息时,我想知道发生了什么变化。

理论上,当我定义 OnSettingChange 并且 Windows 调用它时,lpszSection 应该告诉我正在更改的部分是什么,并且工作正常,但随后我通过调用 SystemParametersInfo 检查给定部分并传入操作 SPI_GETNONCLIENTMETRICS,然后逐步执行调试器和我确保我观察返回的 NONCLIENTMETRICS 中的数据是否有任何字体更改,但没有发生任何字体更改。

即使这不起作用,我应该仍然能够在设置更改时检查 DPI。我真的不会关心其他细节,每次收到 WM_SETTINGCHANGE 消息时,我都会检查 DPI 并执行我感兴趣的操作,但我也无法获得系统 DPI。

我试图通过调用 GetSystemMetrics 方法来获取 DPI,也适用于每个 DC:

Dekstop DC->GetDeviceCaps LOGPIXELSX/LOGPIXELSY 窗口 DC->GetDeviceCaps LOGPIXELSX/LOGPIXELSY 当前 DC->GetDeviceCaps LOGPIXELSX/LOGPIXELSY

即使我在图形属性窗口中更改 DPI,这些值也不会返回任何不同,它们总是显示 96。

有人可以帮我解决这个问题吗?我应该寻找什么?我应该在哪里看?

afx_msg void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
    int windowDPI = 0;
    int deviceDPI = 0;
    int systemDPI = 0;
    int desktopDPI = 0;
    int dpi_00_X = 0;
    int dpi_01_X = 0;
    int dpi_02_X = 0;
    int dpi_03_X = 0;

    CDC* windowDC = CWnd::GetWindowDC(); // try with window DC
    HDC desktop = ::GetDC(NULL); // try with desktop DC
    CDC* device = CWnd::GetDC(); // try with current DC
    HDC hDC = *device; // try with HDC
    if( windowDC )
    {
        windowDPI = windowDC->GetDeviceCaps(LOGPIXELSY); 
        // always 96 regardless if I change the Font 
        // Size to Extra Large Fonts or keep it at Normal

        dpi_00_X = windowDC->GetDeviceCaps(LOGPIXELSX); // 96
    }

    if( desktop )
    {
        desktopDPI = ::GetDeviceCaps(desktop, LOGPIXELSY); // 96
        dpi_01_X = ::GetDeviceCaps(desktop, LOGPIXELSX); // 96
    }

    if( device )
    {
        deviceDPI = device->GetDeviceCaps(LOGPIXELSY); // 96
        dpi_02_X = device->GetDeviceCaps(LOGPIXELSX); // 96
    }

    systemDPI = ::GetDeviceCaps(hDC, LOGPIXELSY); // 96
    dpi_03_X = ::GetDeviceCaps(hDC, LOGPIXELSX); // 96

    CWnd::ReleaseDC(device);
    CWnd::ReleaseDC(windowDC);
    ::ReleaseDC(NULL, desktop);
    ::ReleaseDC(NULL, hDC);

    CWnd::OnWinSettingChange(uFlags, lpszSection);
}

DPI 始终返回 96,但当我将字体大小更改为超大字体或将 DPI 更改为 120(从图形属性)时,设置更改才会生效。

4

6 回答 6

4

[重读后编辑]我几乎肯定更改为“大字体”不会导致 DPI 更改,而是主题设置。您应该能够通过应用“大字体”更改然后打开 DPI 设置所在的高级显示属性来验证,它应该保持在 96dpi。


DPI 更改应该需要重新启动。也许该设置尚未传播到 GetDeviceCaps 可以检索它的地方?

也许尝试更改不需要重新启动的设置(也许是分辨率),然后看看您是否可以检测到更改。如果可以,您的答案可能是直到重新启动后才能检测到 DPI 变化。

于 2008-10-17T12:46:58.527 回答
3

当您在 Desktop DC 上调用 GetDeviceCaps() 时,您是否使用了可能被 MFC 缓存并因此包含过期信息的 DC?您是否从 OnSettingsChange 处理程序内部同步调用 GetDeviceCaps()?我可以看到这些东西中的一个或两个可能如何让您获得过时的 DPI 版本。

Raymond Chen写了这篇文章,他的解决方案看起来像这样(请注意,我添加了 :: 运算符以避免调用 API 的 MFC 包装器):

int GetScreenDPI()
{
  HDC hdcScreen = ::GetDC(NULL);
  int iDPI = -1; // assume failure
  if (hdcScreen) {
    iDPI = ::GetDeviceCaps(hdcScreen, LOGPIXELSX);
    ::ReleaseDC(NULL, hdcScreen);
  }
  return iDPI;
}
于 2008-10-17T11:25:41.357 回答
2

我有预感 WM_THEMECHANGED 会照顾你。不过,它没有任何关于发生了什么变化的暗示。您必须使用 OpenThemeData 并缓存初始设置,然后在每次收到消息时进行比较。

您可能不需要关心发生了什么变化,难道您不能有一个通用的布局例程来调整您的表单/对话框/任何东西,通过考虑所有内容并假设从头开始?

你想解决什么问题?

于 2008-10-17T18:36:09.087 回答
1

请参阅http://msdn.microsoft.com/en-us/library/ms701681(VS.85).aspx,此处对此进行了解释(引用:“如果不取消 dpi 缩放,此调用将返回默认值 96 dpi。”)

于 2008-11-12T22:53:59.900 回答
0

我认为字体大小更改时显示 DPI 不会更改。Windows 可能只是将WM_PAINTandWM_NCPAINT消息发送到所有打开的窗口,并且它们正在使用当前(现在很大)系统字体重新绘制自己。

于 2008-10-17T18:47:37.330 回答
0

查看注册表中的这些值:

Windows XP Theme HKCU\Software\Microsoft\Windows\CurrentVersion\ThemeManager\SizeName 可能的值:NormalSize、LargeFonts 和 ExtraLargeFonts 这些值与语言无关

Windows Classic Theme HKCU\Control Panel\Appearance\Current 可能的值:Windows Classic、Windows Classic(大)、Windows Classic(特大)、Windows Standard、Windows Standard(大)、Windows Standard(特大) 请注意,这些值是语言相关

Windows Vista 不支持此功能。如果我们想要更大的字体,只需更改 DPI 设置。在这种情况下,GetDeviceCaps 应该可以工作。

希望这可以帮助。

于 2009-06-26T20:10:53.250 回答