GDI Accessories and Tools: Fonts


Introduction to Fonts

A font is a list of symbols that can be drawn on a device context to produce a readable message. A font is designed by an artist but usually follows a specific pattern. For example a font designed to produce symbols readable in the English language must be designed by a set of predetermined and agreed upon symbols. These English symbols are grouped in an entity called the English alphabet. When designing such a font, the symbols created must conform to that language. Although this is the general principle of a font, it is possible for a font to be made of a series of non-readable symbols.

Just like everything else in the computer, a font must have a name. To accommodate the visual needs, a font is designed to assume different sizes.

Font Selection

Before using a font to draw text in a device, the font must have been installed on the computer. Microsoft Windows installs many fonts during setup. To handle its various assignments, the operating system uses a particular font known as the System Font. This is the font used to display the menu items and other labels for resources in applications. If you want to use a different font to draw text in your application, you must select it.

Selecting a font, as well as selecting any other GDI object, is equivalent to specifying the characteristics of a GDI object you want to use. To do this, you must first create the font. To select a font, pass it as a pointer to the CDC::SelectObject() method. Its syntax is:

virtual CFont* SelectObject(CFont* pFont);

This method takes as argument the font you want to use, pFont. It returns a pointer to the font that was previously selected. If there was a problem when selecting the font, the method returns NULL.

Font Creation

A font is created as a variable of the CFont class (of course, you can also use the Win32 API's HFONT class). The CFont class is based on the CGdiObject. To declare a CFont variable, you can use the default constructor of this class. This can be easily done as follows:

CFont NewFont;

After declaring a CFont variable, you must initialize it. This can be done by calling one of the Create member functions. The easiest technique of creating a font is done with the CreatePointFont() method. Its syntax is:

BOOL CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, CDC* pDC = NULL);

The nPointSize is the height of the font. It is supplied as a multiple of 1/10.

This method requires two value. The name of the font is specified with the lpszFaceName value. If you do not want to specify a font, you can pass the argument as NULL.

If you have a CDC variable, you can convert the value of the height to logical units. If you do not have this value, set it to NULL.

Here is an example:

void CExoView::OnDraw(CDC* pDC)
	CExoDoc* pDoc = GetDocument();

	CFont font;

	font.CreatePointFont(920, "Garamond");
	CFont *pFont = pDC->SelectObject(&font);
	pDC->TextOut(20, 18, "Christine", 9);


To control the color applied when drawing the text, you can call the CDC::SetTextColor() method. For example, the above name can be drawn in blue as follows:

void CExoView::OnDraw(CDC* pDC)
	CExoDoc* pDoc = GetDocument();

	CFont font;

	font.CreatePointFont(920, "Garamond");
	CFont *pFont = pDC->SelectObject(&font);

	pDC->SetTextColor(RGB(0, 125, 250));
	pDC->TextOut(20, 18, "Christine", 9);


To produce a shadow effect, you can add another copy of the same text on a slightly different location and call the CDC::SetBkMode() method. Here is an example:

void CExoView::OnDraw(CDC* pDC)
	CExoDoc* pDoc = GetDocument();

	CFont font;

	font.CreatePointFont(920, "Garamond");
	CFont *pFont = pDC->SelectObject(&font);

	pDC->SetTextColor(RGB(110, 185, 250));
	pDC->TextOut(26, 24, "Christine", 9);

	pDC->SetTextColor(RGB(0, 0, 255));
	pDC->TextOut(20, 18, "Christine", 9);

Text with shadow effect

One of the most complete means of creating a font is by using the CFont::CreateFont() method. Its syntax is:

BOOL CreateFont(int nHeight,
	       int nWidth,
	       int nEscapement,
	       int nOrientation,
	       int nWeight,
	       BYTE bItalic,
	       BYTE bUnderline,
	       BYTE cStrikeOut,
	       BYTE nCharSet,
	       BYTE nOutPrecision,
	       BYTE nClipPrecision,
	       BYTE nQuality,
	       BYTE nPitchAndFamily,
	       LPCTSTR lpszFacename);

The nHeight argument is the height applied to the text.

The nWidth value is the desired width that will be applied on the text.

The nEscapement is the angle used to orient the text. The angle is calculated as a multiple of 0.1 and oriented counterclockwise.

The nOrientation is the angular orientation of the text with regards to the horizontal axis.

The nWeight is used to attempt to control the font weight of the text because it is affected by the characteristics of the font as set by the designer. It holds values that displays text from thin heavy bold. The possible values are:

Constant Value Constant Value

The bItalic specifies whether the font will be italicized (TRUE) or not (FALSE).

The bUnderline is used to underline (TRUE) or not underline (FALSE) the text.

The cStrikeOut is specifies whether the text should be stroke out (TRUE) or not (FALSE) with a line.

The nCharSet, specifies the character set used. The possible values are:

  Constant Value

The nOutPrecision controls the amount precision used to evaluate the numeric values used on this function for the height, the width, and angles. It can have one of the following values: OUT_CHARACTER_PRECIS, OUT_STRING_PRECIS, OUT_DEFAULT_PRECIS, OUT_STROKE_PRECIS, OUT_DEVICE_PRECIS, OUT_TT_PRECIS, OUT_RASTER_PRECIS

If some characters may be drawn outside of the area in which they are intended, the nClipPrecision is used to specify how they may be clipped. The possible value used are CLIP_CHARACTER_PRECIS, CLIP_MASK, CLIP_DEFAULT_PRECIS, CLIP_STROKE_PRECIS, CLIP_ENCAPSULATE, CLIP_TT_ALWAYS, CLIP_LH_ANGLES.

The nQuality specifies how the function will attempt to match the font's characteristics. The possible values are DEFAULT_QUALITY, PROOF_QUALITY, and DRAFT_QUALITY.

The nPitchAndFamily specifies the category of the font used. It combines the pitch and the family the intended font belongs to. The pitch can be specified with DEFAULT_PITCH, VARIABLE_PITCH, or FIXED_PITCH. The pitch is combined using the bitwise OR operator with one of the following values:

  Value Description
  FF_DECORATIVE Used for a decorative or fancy font
  FF_DONTCARE Let the compiler specify
  FF_MODERN Modern fonts that have a constant width
  FF_ROMAN Serif fonts with variable width
FF_SCRIPT Script-like fonts
FF_SWISS Sans serif fonts with variable width

The lpszFacename is the name of the font used.

Once you have created a font, you can select it into the device context and use it it for example to draw text.

After using a font, you should delete it to reclaim the memory space its variable was using. This is done by calling the CGdiObject::DeleteObject() method.

Here is an example:

void CExoView::OnDraw(CDC* pDC)
    CFont font;

    font.CreateFont(46, 28, 215, 0,
		  DEFAULT_PITCH | FF_ROMAN, "Times New Roman");

    CFont *pFont = pDC->SelectObject(&font);
    pDC->TextOut(20, 128, "Euzhan Palcy", 12);

Select Font

Remember that once a GDI object such as a font has been selected, it remains in the device context until further notice. For example, if you have created and selected a font, any text you draw would follow the characteristics of that font. If you want another font, you must change the previously selected font.

The CFont::CreateFont() method is used to specify all characteristics of a font in one step. Alternatively, if you want to specify each font property, you can declare a LOGFONT variable and initialize it. It is defined as follows:

typedef struct tagLOGFONT { 
  LONG lfHeight; 
  LONG lfWidth; 
  LONG lfEscapement; 
  LONG lfOrientation; 
  LONG lfWeight; 
  BYTE lfItalic; 
  BYTE lfUnderline; 
  BYTE lfStrikeOut; 
  BYTE lfCharSet; 
  BYTE lfOutPrecision; 
  BYTE lfClipPrecision; 
  BYTE lfQuality; 
  BYTE lfPitchAndFamily; 

This time, you don't have to provide a value for each member of the structure and even if you do, you can supply values in the order of your choice. For any member whose value is not specified, the compiler would use a default value but you may not like some of the default values. Therefore, you should specify as many values as possible.

After initializing the LOGFONT variable, call the CFont::CreateFontIndirect() method. Its syntax is:

BOOL CreateFontIndirect(const LOGFONT* lpLogFont);

When calling this member function, pass the LOGFONT variable as a pointer, lpLogFont.

To select the font, call the CDC::SelectObject() method. Once done, you can use the new font as you see fit. Here is an example:

void CExoView::OnDraw(CDC* pDC)
	CFont font;

	LogFont.lfStrikeOut = 0;
	LogFont.lfUnderline = 0;
	LogFont.lfHeight = 42;
	LogFont.lfEscapement = 0;
	LogFont.lfItalic = TRUE;

	CFont *pFont = pDC->SelectObject(&font);
	pDC->TextOut(20, 18, "James Kolowski", 14);


Font Retrieval

If some text is displaying and you want to get the font properties of that text, you can call the CDC::GetLogFont() method. Its syntax is:

int GetLogFont(LOGFONT * pLogFont);

To get the current font characteristics on a device context, pass a LOGFONT variable as a pointer to this method. After execution, it returns the LOGFONT argument with its characteristics. If this method succeeds, it returns TRUE or non-zero. It it fails, it returns FALSE or 0.

Here is an example:

void CAboutDlg::OnButton1() 
	CFont *font;

	font = this->GetFont();
	char StrFont[40];

	strcpy(StrFont, LogFont.lfFaceName);

	CClientDC dc(this);
	dc.TextOut(58, 120, StrFont, strlen(StrFont));	

Home Copyright © 2003-2006 FunctionX, Inc.