簡體   English   中英

無法檢測到 Windows 字體大小何時更改了 C++ MFC

[英]Can't detect when Windows Font Size has changed C++ MFC

我試圖確定如何檢測用戶何時將 Windows 字體大小從普通字體更改為超大字體,通過在 Windows XP 計算機上執行以下步驟來選擇字體大小:

  1. 右鍵單擊桌面並選擇屬性。
  2. 單擊外觀選項卡。
  3. 選擇字體大小:普通/大字體/超大字體

我的理解是字體大小的變化會導致 DPI 的變化,所以這是我迄今為止嘗試過的。


我的目標:

我想檢測Windows 字體大小何時從普通字體變為大字體或超大字體,並根據字體大小的變化采取一些措施。 我假設當 Windows 字體大小改變時,DPI 也會改變(特別是當大小為 Extra Large Fonts 時


到目前為止我嘗試過的:

我收到了幾條消息,包括:WM_SETTINGCHANGE、WM_NCCALCSIZE、WM_NCPAINT 等……但是這些消息都不是字體大小更改時所特有的,換句話說,當我收到 WM_SETTINGSCANGE 消息時,我想知道發生了什么變化。

理論上,當我定義 OnSettingChange 並且 Windows 調用它時,lpszSection 應該告訴我更改部分是什么,並且工作正常,但是然后我通過調用 SystemParametersInfo 檢查給定部分並傳入操作 SPI_GETNONCLIENTMETRICS,然后我逐步完成調試器,我確保我在返回的 NONCLIENTMETRICS 中查看任何字體更改的數據,但沒有發生任何更改。

即使這不起作用,當設置更改時,我仍然應該能夠檢查 DPI。 我真的不會關心其他細節,每次收到 WM_SETTINGCHANGE 消息時,我只會檢查 DPI 並執行我有興趣執行的操作,但我也無法獲得系統 DPI。

我試圖通過調用 GetSystemMetrics 方法來獲取 DPI,也適用於每個 DC:

桌面 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(從圖形屬性)時,設置更改會生效。

[重讀后編輯]我幾乎肯定更改為“大字體”不會導致 DPI 更改,而是主題設置。 您應該能夠通過應用“大字體”更改然后打開 DPI 設置所在的高級顯示屬性來驗證,它應該保持在 96dpi。


DPI 更改應該需要重新啟動。 也許該設置尚未傳播到 GetDeviceCaps 可以檢索它的地方?

也許嘗試更改不需要重新啟動的設置(可能是分辨率),然后查看是否可以檢測到更改。 如果可以,您的答案可能是在重新啟動之前您無法檢測到 DPI 更改。

當您在桌面 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;
}

我有預感 WM_THEMECHANGED 會照顧好你。 不過,它沒有任何關於發生了什么變化的暗示。 您必須使用 OpenThemeData 並緩存初始設置,然后在每次收到消息時進行比較。

您可能不需要關心發生了什么變化,難道您不能有一個通用的布局例程,通過考慮所有內容並假設從頭開始來調整您的表單/對話框/任何內容嗎?

你想解決什么問題?

請參閱http://msdn.microsoft.com/en-us/library/ms701681(VS.85).aspx ,這在那里進行了解釋(引用:“如果您不取消 dpi 縮放,此調用將返回默認值 96 dpi。”)

查看注冊表中的這些值:

Windows XP 主題 HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager\\SizeName 可能的值:NormalSize、LargeFonts 和 ExtraLargeFonts 這些值與語言無關

Windows 經典主題 HKCU\\控制面板\\外觀\\當前 可能的值:Windows 經典、Windows 經典(大)、Windows 經典(特大)、Windows 標准、Windows 標准(大)、Windows 標准(特大) 請注意,這些值是語言依賴

Windows Vista 不支持此功能。 如果我們想要更大的字體,只需更改 DPI 設置。 在這種情況下,GetDeviceCaps 應該可以工作。

希望這可以幫助。

我認為當字體大小改變時,顯示 DPI 不會改變。 Windows 可能只是將WM_PAINTWM_NCPAINT消息發送到所有打開的窗口,並且它們正在使用當前(現在很大)的系統字體重新繪制自己。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM