Home

GDI Accessories: Fonts

 

Fonts

 

Introduction to Fonts

A font is a technique of representing symbols drawn on a device context. 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. This also implies that one font can be significantly different from another and a font is not necessarily a series of readable symbols.

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

Before drawing text on a device context, a font must have been installed. 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.

The Win32 library makes fonts available through the HFONT handle. The VCL provides font support through the TFont class.

Font Creation or Selection

When Windows starts, it creates and selects a font to use throughout your application. If you do not like that font, you can select another. Selecting a font, as well as selecting any other GDI object we will use from now on, is equivalent to specifying the characteristics of a GDI object you want to use. To do this, you must first create the object, unless it exists already.

To create a font, you can declare a TFont variable. If you want to use a temporary font in an event, you can declare the variable locally. If you plan to refer to the same font object in more than one event, you should declare it globally in the header file of the parent object that will make it available to necessary controls.

After declaring a TFont variable, you must initialize it. This can be done by assigning the desired values to its member variables. You do not have to specify a value for each characteristic of the font. If you omit a property, its default value would be used.

To perform text drawing on a device context, the TCanvas class is equipped with a Font member variable. This variable has a set of default values. For example, the color of text is set to black. To specify different font characteristics, simply call the Font member variable and initialize any of its own member variables as you see fit. In the same way, if you first declare a TFont variable, initialize it, and want to use it in the device context, simply assign it to the TCanvas::Font variable. This would be done as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	TFont *NewFont = new TFont;

	Canvas->Font = NewFont;
}
//---------------------------------------------------------------------------

You can also create a font using one of the many Win32 font related functions.

Font Properties

Although sometimes represented as if it were one entity object, a font can be a complex concept made of various characteristics such as its width, weight, and size, etc. Therefore, to make better use of fonts, you should be familiar with their appearance, especially if you plan to perform any artistic text drawing.

The name of a font is the most commonly used characteristic. It is used by the operating system and the application to identify it. The names of fonts installed on your computer can be seen in the Fonts window accessible from Control Panel:

To use a particular font, assign its name to the Name member variable of the TFont class. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	TFont *NewFont = new TFont;

	NewFont->Name = "Garamond";
	Canvas->Font = NewFont;
	Canvas->TextOut(20, 18, "Christine");
}
//---------------------------------------------------------------------------

If you are specifying a font other than the default to use in your application, you should use only the most popular font that are more likely to be found on your userís computers. Otherwise, the result may be unpredictable.

The height of a font is a measure of the height used to represent its characters. It is represented by the Height property of the TFont class.

The font size is the dimension of characters used to represent the font on a device context. It is specify using the TFont::Size member variable. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	Canvas->Font->Size = 120;
	Canvas->Font->Name = "Garamond";

	Canvas->TextOut(26, 24, "Christine");
}
//---------------------------------------------------------------------------

The Style of a font controls how the font displays, in normal, italicized, underlined, stroke out, some of these characteristics or all of them. The VCL manages these properties as a set; meaning you can build them, add those you want or retract those you do not need. The available characteristics are as follows:

Characteristic Value Example
Bold fsBold This text is bold
Italic fsItalic Italicized section
Underline fsUnderline The words are underlined
Strikeout fsStrikeOut Stroke out but happy

Font styles are implemented through the TFontStyles property. To control the Style of font, you must call TFontStyles and use the extraction operators to add or subtract a style. To add a style, you can use the << operator. For example, suppose you want to apply a Bold style to a Memo control. You can use the << operator as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	Memo1->Font->Name = "Verdana";
	Memo1->Font->Size = 10;
	Memo1->Font->Style = TFontStyles() << fsBold;
}
//---------------------------------------------------------------------------

In the same way, you can add other styles using the << operator:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	Memo1->Font->Name = "Verdana";
	Memo1->Font->Size = 10;
	Memo1->Font->Color = clBlue;
	Memo1->Font->Style = TFontStyles() << fsBold << fsUnderline
					   << fsItalic << fsStrikeOut;
}
//---------------------------------------------------------------------------

Unlike the Win32 functions as we will see, the TFont class provide support for colors. Therefore, to draw text using a color of your choice, assign its value to the TFont::Color property. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	Canvas->Font->Size = 120;
	Canvas->Font->Color = clSkyBlue;
	Canvas->Font->Name = "Garamond";

	SetBkMode(Canvas->Handle, TRANSPARENT);

	Canvas->TextOut(26, 24, "Christine");

	Canvas->Font->Color = clBlue;
	Canvas->TextOut(20, 18, "Christine");
}
//---------------------------------------------------------------------------
 

Win32 Support of Fonts

As the main library of Windows applications, Win32 provides font support through various functions. Most of these functions return an HFONT value. To use them, call any of the Win32 functions and make sure you retrieve its return value. Then assign that value to the Handle member variable of the TCanvas class.

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

The Win32 functions that are related to fonts do not control the color applied when drawing text on a device context. To provide color, you can call the SetTextColor() function as we saw in the previous lesson.

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

HFONT CreateFont(int nHeight,
		 int nWidth,
		 int nEscapement,
		 int nOrientation,
		 int fnWeight,
		 DWORD fdwItalic,
		 DWORD fdwUnderline,
		 DWORD fdwStrikeOut,
		 DWORD fdwCharSet,
		 DWORD fdwOutputPrecision,
		 DWORD fdwClipPrecision,
		 DWORD fdwQuality,
		 DWORD fdwPitchAndFamily,
		 LPCTSTR lpszFace);

The nHeight parameter is the height of a small rectangle in which a character of this font would fit.

The nWidth value is the average width of characters of this font. If you know the width to apply, then you can pass it as this argument. If not, pass it as 0. In this case, the system will choose the closest value to be applied on the text.

The nEscapement parameter is the angle used to orient the text. The angle is calculated as a multiple of 0.1, oriented counterclockwise and provided in degrees.

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

The fnWeight parameter 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 to heavy bold. The possible values are:

Constant Value   Constant Value
FW_DONTCARE 0   FW_THIN 100
FW_EXTRALIGHT 200   FW_ULTRALIGHT 200
FW_LIGHT 300      
FW_NORMAL 400   FW_REGULAR 400
FW_MEDIUM 500      
FW_SEMIBOLD 600   FW_DEMIBOLD 600
FW_BOLD 700      
FW_EXTRABOLD 800   FW_ULTRABOLD 800
FW_BLACK 900   FW_HEAVY 900

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

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

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

The fdwCharSet parameter specifies the character set used. The possible values are: ANSI_CHARSET, BALTIC_CHARSET, CHINESEBIG5_CHARSET, DEFAULT_CHARSET, EASTEUROPE_CHARSET, GB2312_CHARSET, GREEK_CHARSET, HANGUL_CHARSET, MAC_CHARSET, OEM_CHARSET, RUSSIAN_CHARSET, SHIFTJIS_CHARSET, SYMBOL_CHARSET,
TURKISH_CHARSET, HEBREW_CHARSET, and THAI_CHARSET.

The fdwOutPrecision parameter controls the amount of 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_DEFAULT_PRECIS, OUT_DEVICE_PRECIS, OUT_OUTLINE_PRECIS, OUT_RASTER_PRECIS, OUT_STRING_PRECIS, OUT_STROKE_PRECIS, OUT_TT_ONLY_PRECIS, and OUT_TT_PRECIS.

The fdwClipPrecision parameter is used to specify how some characters may be drawn outside of the area in which they are intended. The possible values used are CLIP_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS, CLIP_STROKE_PRECIS, CLIP_MASK, CLIP_EMBEDED, CLIP_LH_ANGLES, and CLIP_TT_ALWAYS.

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

The fdwPitchAndFamily parameter 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 fonts
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 lpszFace string is the name of the font used.

Once you have created a font, you can assign its return HFONT value to the handle of the TCanvas::Font member variable and then use it as you see fit. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	HFONT font;

	font = CreateFont(46, 28, 215, 0,
			  FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
			  OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
			  DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,
			  "Times New Roman");

	Canvas->Font->Handle = font;
	Canvas->TextOut(20, 128, "Euzhan Palcy");
}
//---------------------------------------------------------------------------

Remember that once a device context object, such as a font, has been selected, it remains there 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 CreateFont() function 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; 
	TCHAR lfFaceName[LF_FACESIZE]; 
} LOGFONT, *PLOGFONT;

This time, you do not 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. The member variables can be initialized with their equivalent values we reviewed for the CreateFont() function.

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

HFONT CreateFontIndirect(CONST LOGFONT *lplf);

When calling this member function, pass the LOGFONT variable as a pointer, lplf. Like CreateFont(), the CreateFontIndirect() function returns an HFONT value. After calling this function, you can retrieve its return value and initialize the handle of the TCanvas::Font member variable. After that assignment, the font is ready for you. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	HFONT font;
	LOGFONT LogFont;

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

	font = CreateFontIndirect(&LogFont);
	Canvas->Font->Handle = font;

	Canvas->TextOut(20, 18, "James Kolowski");
}
//---------------------------------------------------------------------------
 

Font Retrieval

At any specific time, a font is selected in the device context. This font could be the default font set by the operating system, which is usually MS Sans Serif. You may have changed it because of the requirements of your application. If you want to find out what font is currently selected on the canvas, simple declare a TFont variable and initialize it with the TCanvas::Font member variable. This could be done as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
	TFont *CurFont = Canvas->Font;
}
//---------------------------------------------------------------------------

After this initialization, your variable can provide you with any type of valid information related to the currently selected font on the device context, such as the fontís name, its size, its style(s), character set, etc.

Font Methods

The TFont class is equipped with a constructor that can be used to declare its variable. Like every TObject descendent, a TFont variable must be declared using the new operator. After using it, you can delete it using the delete operator.

If the system or you have created or selected a font, you can use it to initialize another font variable. To support this, the TFont class is equipped with the Assign() method. Its syntax is:

virtual void __fastcall Assign(Classes::TPersistent* Source);

The Source parameter is the returned new font. After the font variable calls it, it would hold the same characteristics of the existing font. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
	TFont *CurFont = new TFont;
	Canvas->Font->Assign(CurFont);

	Caption = CurFont->Name;
}
//---------------------------------------------------------------------------

As seen on this example, the TFont::Assign() method can be used to retrieve the current font selected in the device context.

Font Messages and Events

On most graphical applications created in an environment such as C++ Builder, device context objects come and go regularly to make the application less boring. Many, if not most, of the device context objects we will use are derived from the TGraphicsObject class. When a device object changes, the parent class fires the OnChange() event. OnChange() is a TNotifyEvent type of event.

Home Copyright © 2005-2007 FunctionX, Inc.