Create a font with the desired size

Let’s asume you want to change the font of a window\control and for the sake of simplicity let’s consider an MFC dialog application. In that case, there are several steps you should follow:

  • declare a CFont variable in the dialog class
  • create the font in OnInitDialog (using CreateFont)
  • set the font to the control (using SetFont)

For example, say that you want to use Arial size 12 for a multiline edit control. In that case you could put the following code in OnInitDialog:

BOOL CFontSampleDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog();   

	// Set the icon for this dialog.  The framework does this automatically 
	//  when the application's main window is not a dialog 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	SetIcon(m_hIcon, FALSE);		// Set small icon   

	VERIFY(editFont.CreateFont( 
		12,                        // nHeight 
		0,                         // nWidth 
		0,                         // nEscapement 
		0,                         // nOrientation 
		FW_NORMAL,                 // nWeight 
		FALSE,                     // bItalic 
		FALSE,                     // bUnderline 
		0,                         // cStrikeOut 
		ANSI_CHARSET,              // nCharSet 
		OUT_DEFAULT_PRECIS,        // nOutPrecision 
		CLIP_DEFAULT_PRECIS,       // nClipPrecision 
		DEFAULT_QUALITY,           // nQuality 
		DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily 
		_T("Arial")));             // lpszFacename   

	GetDlgItem(IDC_EDIT_SAMPLE)->SetFont(&editFont);   

	return TRUE;  // return TRUE  unless you set the focus to a control 
}

The result should be the following:

control with Arial of wrong size

Look carefully and you’ll see that’s not the right size 12? Why? Because the height and width (which doesn’t matter in this case) parameters for CreateFont() are given in logical units and not pixels. When you passed 12 we meant pixels, so to correctly create a font of size 12 pixels, you must convert from pixels to logical units. To do that, you need to determine the number of pixels per logical inch along the screen height. For that you have to use GetDeviceCaps() with the appropriate device context. To compute the actual value, MulDiv() is used. This function multiplies two 32-bit integers and devides the 64-bit result by a third 32-bit integer.

In this case, OnInitDialog() becomes:

BOOL CFontSampleDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog();   

	// Set the icon for this dialog.  The framework does this automatically 
	//  when the application's main window is not a dialog 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	SetIcon(m_hIcon, FALSE);		// Set small icon   

	CDC* pDC = GetDC(); 
	int desiredHeight = 12; 
	int height = -MulDiv(desiredHeight, pDC->GetDeviceCaps(LOGPIXELSY), 72); 
	ReleaseDC(pDC);   

	VERIFY(editFont.CreateFont( 
		height,                    // nHeight 
		0,                         // nWidth 
		0,                         // nEscapement 
		0,                         // nOrientation 
		FW_NORMAL,                 // nWeight 
		FALSE,                     // bItalic 
		FALSE,                     // bUnderline 
		0,                         // cStrikeOut 
		ANSI_CHARSET,              // nCharSet 
		OUT_DEFAULT_PRECIS,        // nOutPrecision 
		CLIP_DEFAULT_PRECIS,       // nClipPrecision 
		DEFAULT_QUALITY,           // nQuality 
		DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily 
		_T("Arial")));             // lpszFacename   

	GetDlgItem(IDC_EDIT_SAMPLE)->SetFont(&editFont);   

	return TRUE;  // return TRUE  unless you set the focus to a control 
}

and the result is:

Arial with correct size 12 pixels

and that is what we wanted in the first place.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.