Hungry Mind , Blog about everything in IT - C#, Java, C++, .NET, Windows, WinAPI, ...

Changing dialog font in MFC

Редактор диалогов Visual Studio позволяет задать базовый шрифт для диалога.

По умолчанию, это MS Shell Dlg 8-го размера. А что, если я хочу выставить Segoe UI? Точнее, что будет на системах, где этого шрифта физически нет? Не известно.

Уже понятно, что сию беду нужно, как обычно, писать в коде. Ниже - два универсальных способа решить проблему.

Способ 1

У класса CDialog имеется следующая функция-член: virtual BOOL CreateIndirect(LPCDLGTEMPLATE, CWnd*, void*); Создание любого диалога проходит через нее, поэтому для изменения шрифта в шаблоне диалога это очень подходящее место. В результате - создаем класс-потомок CDialog, переопределяем CreateIndirect, меняем шрифт, вызываем базовый метод. Недостаток этого подхода - все классы диалогов нужно будет наследовать от него. Вариант подходит для нового кода, а если в проекте уже 120 диалогов - что делать?

Способ 2

Хак, а как же еще?

class CFontOccManager : public COccManager
{
    virtual const DLGTEMPLATE *PreCreateDialog(_AFX_OCC_DIALOG_INFO *pOccDialogInfo, const DLGTEMPLATE *pOrigTemplate) {
        const DLGTEMPLATE *lpNewTemplate = __super::PreCreateDialog(pOccDialogInfo, pOrigTemplate);

        OSVERSIONINFO osvi;
        ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
        GetVersionEx(&osvi);

        if ((osvi.dwMajorVersion >= 6) && !pOccDialogInfo->m_pNewTemplate) {
            CDialogTemplate dlgTemplate(lpNewTemplate);

            CString origFontFaceName;
            WORD wOrigFontSize;
            dlgTemplate.GetFont(origFontFaceName, wOrigFontSize);

            NONCLIENTMETRICS ncm;
            ncm.cbSize = sizeof(NONCLIENTMETRICS);
            SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
            LOGFONT lf = ncm.lfMessageFont;
            HDC hDC = ::GetDC(NULL);
            const int logPixelSY = ::GetDeviceCaps(hDC, LOGPIXELSY);
            ::ReleaseDC(NULL, hDC);
            const WORD wProposedFontSize = static_cast<WORD>(MulDiv(-lf.lfHeight, 72, logPixelSY));
            dlgTemplate.SetFont(lf.lfFaceName, max(wOrigFontSize, wProposedFontSize));
            pOccDialogInfo->m_pNewTemplate = reinterpret_cast<DLGTEMPLATE*>(dlgTemplate.Detach());
            return(pOccDialogInfo->m_pNewTemplate);
        }
        else
            return(lpNewTemplate);
    }
};


AfxEnableControlContainer(new CFontOccManager());

Класс COccManager не документирован, но создание диалога проходит в том числе через него. Логика простая:

  1. проверить версию Windows (наличие шрифта Segoe UI);
  2. получить метрики экрана;
  3. выбрать нужный набор метрик и посчитать размер шрифта;
  4. поменять шрифт в шаблоне диалога.

В качестве метрик я взял характеристики lfMessageFont - LOGFONT structure that contains information about the font used in message boxes. Message box - это же диалог, остальное не подходит. Код простой, объяснений не требует. Единственный нюанс, я беру максимум из старого размера и посчитанного.

В результате - нормального размера диалоги с обалденным шрифтом. Удачи.

1 коммент.:

Анонимный комментирует...

Hello, Neat post. There is a problem along with your website in internet explorer, would check this?
IE still is the market leader and a big portion of folks will leave out your magnificent
writing because of this problem.
Feel free to surf my blog post GFI Norte

Отправить комментарий

Copyright 2007-2011 Chabster