无法检测到Windows字体大小是否已更改C ++ MFC

问题描述 投票:8回答:6

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

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

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


我的目标:

我想检测Windows字体大小何时从“正常”更改为“大字体”或“超大字体”,并根据该字体大小的变化采取一些措施。我认为,当Windows字体大小更改时,DPI也将更改(尤其是当字体为“超大字体”时)>


到目前为止我尝试过的:

我收到几条消息,包括:WM_SETTINGCHANGE,WM_NCCALCSIZE,WM_NCPAINT等...,但是这些消息都不是字体大小更改时唯一的情况,换句话说,当我收到WM_SETTINGSCHANGE消息时,我想知道更改了什么。

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

即使那行不通,当设置更改时,我仍然应该能够检查DPI。我真的不在乎其他细节,每次收到WM_SETTINGCHANGE消息时,我只会检查DPI并执行我有兴趣执行的操作,但我也无法获取系统DPI。] >

我也尝试通过对每个DC调用GetSystemMetrics方法来获取DPI:

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,但是当我将字体大小更改为Extra Large Fonts或将DPI更改为120(从图形属性)时,设置更改确实会生效。

[我正在尝试确定如何检测用户何时将Windows字体大小从“标准”更改为“超大字体”,通过在Windows XP上执行以下步骤来选择字体大小...

]

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


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

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

我有预感,WM_THEMECHANGED会照顾您的。不过,它没有任何提示。您将必须使用OpenThemeData并缓存初始设置,然后在每次收到消息时进行比较。

虽然您可能不需要关心发生了什么变化,但是您是否不能拥有一个通用布局例程来通过考虑所有因素并假设从头开始调整表单/对话框/其他内容?

您要解决什么问题?

当您在桌面DC上调用GetDeviceCaps()时,您是否正在使用可能由MFC缓存的DC,因此其中包含过时的信息?您是从OnSettingsChange处理程序内部同步进行GetDeviceCaps()调用吗?我可以看到这两种情况之一或全部如何使您过时的DPI版本。

Raymond Chen wrote about this及其解决方案如下(请注意,我添加了::运算符,以避免调用API的MFC包装器:]

int GetScreenDPI()
{
  HDC hdcScreen = ::GetDC(NULL);
  int iDPI = -1; // assume failure
  if (hdcScreen) {
    iDPI = ::GetDeviceCaps(hdcScreen, LOGPIXELSX);
    ::ReleaseDC(NULL, hdcScreen);
  }
  return iDPI;
}

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

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

查看注册表中的这些值:

Windows XP主题HKCU \软件\ Microsoft \ Windows \ CurrentVersion \ ThemeManager \ SizeName可能的值:NormalSize,LargeFonts和ExtraLargeFonts这些值是与语言无关

Windows经典主题HKCU \控制面板\外观\当前可能的值:Windows Classic,Windows Classic(大),Windows Classic(大),Windows Standard,Windows Standard(大),Windows Standard(大)请注意,这些值是与语言有关

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

希望这会有所帮助。

c++ winapi mfc font-size system-font
6个回答
4
投票

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


2
投票

我有预感,WM_THEMECHANGED会照顾您的。不过,它没有任何提示。您将必须使用OpenThemeData并缓存初始设置,然后在每次收到消息时进行比较。

虽然您可能不需要关心发生了什么变化,但是您是否不能拥有一个通用布局例程来通过考虑所有因素并假设从头开始调整表单/对话框/其他内容?


2
投票

当您在桌面DC上调用GetDeviceCaps()时,您是否正在使用可能由MFC缓存的DC,因此其中包含过时的信息?您是从OnSettingsChange处理程序内部同步进行GetDeviceCaps()调用吗?我可以看到这两种情况之一或全部如何使您过时的DPI版本。

Raymond Chen wrote about this及其解决方案如下(请注意,我添加了::运算符,以避免调用API的MFC包装器:]


1
投票

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


0
投票

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


0
投票

查看注册表中的这些值:

Windows XP主题HKCU \软件\ Microsoft \ Windows \ CurrentVersion \ ThemeManager \ SizeName可能的值:NormalSize,LargeFonts和ExtraLargeFonts这些值是与语言无关

© www.soinside.com 2019 - 2024. All rights reserved.