Не удается определить, когда размер шрифта Windows изменился C ++ MFC

Я пытаюсь определить, как я могу определить, когда пользователь меняет размер шрифта Windows с обычного на сверхбольшие шрифты, размер шрифта выбирается путем выполнения следующих шагов на компьютере с Windows XP:

  1. Щелкните правой кнопкой мыши на рабочем столе и выберите «Свойства».
  2. Щелкните вкладку «Внешний вид».
  3. Выберите размер шрифта: Обычный / Крупный шрифт / Очень крупный шрифт.

Насколько я понимаю, изменение размера шрифта приводит к изменению DPI, поэтому вот что я пробовал до сих пор.


Моя цель:

Я хочу определить, когда размер шрифта Windows изменился с обычного на крупный или очень крупный шрифт, и предпринять некоторые действия в зависимости от этого изменения размера шрифта. Я предполагаю, что при изменении размера шрифта Windows изменится и DPI (особенно, если размер шрифта Extra Large Fonts


Что я пробовал до сих пор:

Я получаю несколько сообщений, в том числе: WM_SETTINGCHANGE, WM_NCCALCSIZE, WM_NCPAINT и т.д., но ни одно из этих сообщений не является уникальным для ситуации, когда размер шрифта изменяется, другими словами, когда я получаю сообщение WM_SETTINGSCHANGE, я хочу знать, что изменилось.

Теоретически, когда я определяю OnSettingChange и Windows вызывает его, lpszSection должен сказать мне, что такое изменяемый раздел, и это работает нормально, но затем я проверяю данный раздел, вызывая SystemParametersInfo, и я передаю действие SPI_GETNONCLIENTMETRICS, и я перехожу через отладчик, и я проверяю данные в возвращенной NONCLIENTMETRICS на предмет каких-либо изменений шрифта, но ничего не происходит.

Даже если это не сработает, я все равно смогу проверить DPI при изменении настроек. Меня действительно не волнуют другие детали, каждый раз, когда я получаю сообщение WM_SETTINGCHANGE, я просто проверяю DPI и выполняю действия, которые меня интересуют, но я также не могу получить системный DPI.

Я попытался получить DPI, вызвав метод GetSystemMetrics, также для каждого 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, но изменения настроек ДЕЙСТВИТЕЛЬНО вступают в силу, когда я изменяю размер шрифта на Extra Large Fonts или если я изменяю DPI на 120 (в свойствах графики).


person Kiril    schedule 16.10.2008    source источник


Ответы (6)


[РЕДАКТИРОВАТЬ после перечитывания] Я почти уверен, что переход на «Крупные шрифты» не вызывает изменения DPI, это скорее настройка темы. Вы должны иметь возможность проверить, применив изменение «Крупные шрифты», а затем открыв дополнительные свойства отображения, в которых находится параметр DPI, он должен был остаться на 96 dpi.


Предполагается, что для изменения DPI требуется перезагрузка. Может быть, настройка не распространилась в место, откуда GetDeviceCaps может ее получить?

Возможно, попробуйте изменить параметр, не требующий перезагрузки (возможно, разрешение), а затем посмотрите, сможете ли вы обнаружить это изменение. Если вы можете, ваш ответ, вероятно, заключается в том, что вы не можете обнаружить изменение DPI до перезагрузки.

person Aidan Ryan    schedule 17.10.2008
comment
Но для изменения размера шрифта не требуется перезагрузка, и изменения вступают в силу без перезагрузки ... система ДОЛЖНА отправлять какое-то сообщение в окна, иначе как они узнают об изменении размера шрифта? - person Kiril; 17.10.2008
comment
Извините за многократные повторные правки, мне просто нужно было убедиться, что я удалил из кода всю не относящуюся к делу информацию ... Я попробовал некоторые из ваших решений, и мне пришлось вернуться и отредактировать, чтобы у меня была самая последняя версия здесь комментарии :) извините еще раз! Спасибо за вашу помощь. - person Kiril; 17.10.2008
comment
Для изменения настроек DPI требуется выход из системы и вход в систему (начиная с Windows 7) - person Ian Boyd; 18.07.2011

У меня есть подозрение, что WM_THEMECHANGED позаботится о вас. Однако в нем нет ни малейшего намека на то, что изменилось. Вам нужно будет использовать исходные настройки OpenThemeData и кеша, а затем сравнивать каждый раз, когда вы получаете сообщение.

Вам, вероятно, не нужно заботиться о том, что изменилось, но разве у вас нет универсальной процедуры макета, которая корректирует вашу форму / диалог / что угодно, принимая все во внимание и предполагает, что начинается с нуля?

Какую проблему ты пытаешься решить?

person Aidan Ryan    schedule 17.10.2008
comment
Долгая история, в основном оригинальные разработчики не понимали, что размер шрифта Windows изменится, и они не справились с ситуацией, когда она действительно изменится :) ... теперь я должен это сделать :). Я попробую ваше предложение, и если оно сработает, я сообщу вам как можно скорее :). - person Kiril; 17.10.2008
comment
Изменение размера шрифта - лишь один из случаев, с которыми вам нужно справиться. Вам действительно стоит взглянуть на такой механизм компоновки: codeproject.com/KB/MFC/ UltimateToolbox_Layout.aspx. На codeproject есть много хороших. - person Aidan Ryan; 18.10.2008

Когда вы вызываете GetDeviceCaps () на настольном контроллере домена, возможно, вы используете контроллер домена, который может быть кэширован MFC и, следовательно, содержит устаревшую информацию? Вы выполняете вызов GetDeviceCaps () синхронно из обработчика OnSettingsChange? Я мог видеть, как одна или обе эти вещи могут дать вам устаревшую версию DPI.

Рэймонд Чен писал об этом, и его решение выглядело следующим образом (Примечание которые я добавил :: операторы, чтобы избежать вызова MFC-оболочек API):

int GetScreenDPI()
{
  HDC hdcScreen = ::GetDC(NULL);
  int iDPI = -1; // assume failure
  if (hdcScreen) {
    iDPI = ::GetDeviceCaps(hdcScreen, LOGPIXELSX);
    ::ReleaseDC(NULL, hdcScreen);
  }
  return iDPI;
}
person Tim Farley    schedule 17.10.2008
comment
Каким образом не работает? Вы по-прежнему получаете неизменную настройку DPI при вызове функции, как написано выше? - person Tim Farley; 17.10.2008

См. http://msdn.microsoft.com/en-us/library/ms701681(VS.85).aspx, это объясняется там (цитата: «Если вы не отмените масштабирование dpi, этот вызов вернет значение по умолчанию 96 dpi.»)

person Community    schedule 12.11.2008

Я не думаю, что разрешение дисплея меняется при изменении размера шрифта. Windows, вероятно, просто отправляет сообщения WM_PAINT и WM_NCPAINT во все открытые окна, и они перерисовывают себя, используя текущий (теперь большой) системный шрифт.

person jeffm    schedule 17.10.2008

Посмотрите на эти значения в реестре:

Тема Windows XP 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 должен работать.

Надеюсь это поможет.

person Community    schedule 26.06.2009