Home

GDI Accessories

 

Colors

 

Introduction

The color is one the most fundamental aspects used to enhance the aesthetic appearance of an object. It is a non-spatial abstract that is added to an object to modify some of its visual aspects. The Win32 library provides various functions to deal with colors.

To provide support for colors, the VCL is equipped with the TColor enumerator for the actions you can use to take advantage of the various aspects of colors.

Three numeric values are used to create or specify a color. Each one of these values is 8 bits. The first number is called red. The second is called green. The third is called blue:

Bits
Red 
7 6 5 4 3 2 1 0
Green 
7 6 5 4 3 2 1 0
Blue
7 6 5 4 3 2 1 0

Converted to decimal, each one of these numbers would produce:

27 + 26 + 25 + 24 + 23 + 22 + 21 + 20 
= 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= 255

Therefore, each number can have a value that ranges from 0 to 255 in the decimal system. These three numbers are combined to produce a single value as follows:

23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Blue Green Red

Converted to decimal, this number has a value of 255 * 255 * 255 = 16581375. This means that we can have approximately 16 million colors available.

The Color as a Data Type

Microsoft Windows characterizes a color as a 32-bit long integer value. Therefore, a color is actually a combination of 32 bits. The bits of the most significant byte (the left byte) are reserved for the operating system's internal use and must be set to 0. Based on this, each color is characterized by its combination of a red, a green, and a blue values.

The 32-bit numeric value used by the Win32 library to characterize a color is defined as the COLORREF data type. You can use it to declare a color variable. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	COLORREF ClrMine;
	Color = ClrMine;
}
//---------------------------------------------------------------------------

When or after declaring such a variable, you can initialize it with a 32-bit decimal value. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	COLORREF ClrMine = 1637623;
}
//---------------------------------------------------------------------------

The VCL itself defines a color as a member of the TColor enumerator. Although you can use the COLORREF data type to declare or use a color, you should always cast your color variables to TColor. Otherwise, most of the time, you will receive a nevertheless and somewhat harmless warning. For example, the above COLORREF value can be used to colorize the client area of a form after being cast to TColor as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	COLORREF ClrMine = 1637623;
	Color = TColor(ClrMine);
}
//---------------------------------------------------------------------------

Although the above number (1637623) is a legitimate color value, it is difficult to identify and predict as its red, green, and blue values are not known. To create a color value, the Win32 API provides the RGB macro. Its syntax is:

COLORREF RGB(BYTE byRed, BYTE byGreen, BYTE byBlue);

The RGB macro behaves like a function and requires three numeric values separated by a comma. Each value must range between 0 and 255 both included. Using RGB, the above initialization can be done as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	COLORREF ClrMine = RGB(247, 252, 24);
	Color = TColor(ClrMine);
}
//---------------------------------------------------------------------------

You can also declare a color using the TColor enumerator as a data type. Like any other, the variable can have any valid C++ name. After declaring the variable, you can initialize it. To do this, you can assign it any long integer value. You can also use the RGB macro to create the color. Whether using a constant long or the RGB macro, you should always cast the value to TColor. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	TColor FirstColor = TColor(723873);
	TColor SecondColor = TColor(RGB(247, 252, 24));
}
//---------------------------------------------------------------------------

You can also initialize a TColor variable using a color name as we will review below.

Color Decoding

Whether a color was initialized with a 32-bit long integer, the RGB macro, or a valid color name, if you want to retrieve the red, green, and blue values of a color, you can use the GetRValue(), the GetGValue(), and/or the GetBValue() macros to extract the value of each. The syntaxes of these macros are:

BYTE GetRValue(DWORD rgb);
BYTE GetGValue(DWORD rgb);
BYTE GetBValue(DWORD rgb);

Each macro takes a 32-bit value as argument, rgb. The GetRValue() macro returns the red value of the rgb parameter. The GetGValue() macro returns the green value of the rgb number. The GetBValue() macro returns the blue value of rgb.

Color Identification

When all three red, green, and blue numbers of a color have their lowest value, which is 0, the color is referred to black. When the numbers are at their highest value, which is 255, the color qualifies as white. To help with color naming, the VCL provides a list of color identifiers in the graphics.hpp header file. These names can be used throughout any VCL application where a color would be used. To see a list of these colors, on the Object Inspector, click the Color (or any color-related) field and click the arrow of its combo box. The names of colors start with cl.

There are two categories of color names you will use in your applications: those used or configured by the operating system and those defined by the VCL. The colors whose values are controlled by the operating system are set using the Appearance tab of the Display program of Control Panel:

Just like you, because users are able and free to change these colors to their liking, it is almost impossible to predict the appearance of these colors on someone elseís computer. Fortunately, if you want to use one of these colors, you can ask your application to check its value on the userís computer. To do this, you can call the GetSysColor() function. Its syntax is:

DWORD GetSysColor(int nIndex);

This function receives a constant value that is defined in the operating system representing one of the appearanceís colors and returns the 32-bit value of that color. The colors defined in Control Panel and/or the VCL and can be passed as the nIndex argument of the GetSysColor() function are:

System Color Role: Color of System Color - nIndex TColor Color Name
3D Objects Background COLOR_3DFACE
COLOR_BTNFACE
clBtnFace
3D Objects: Top and Left Edges COLOR_3DHILIGHT
COLOR_3DHIGHLIGHT
COLOR_BTNHILIGHT
COLOR_BTNHIGHLIGHT
clBtnHighlight
3D Objects: Right and Bottom Edges COLOR_3DDKSHADOW cl3DDkShadow
3D Effect of Buttons and Dialog Boxes: Top and left edges COLOR_3DLIGHT cl3DLight
3D Effect of Buttons and Dialog Boxes: Right and bottom edges COLOR_3DSHADOW
COLOR_BTNSHADOW
clBtnShadow
Background of Buttons and Dialog Boxes COLOR_BTNFACE clBtnFace
Text of Buttons COLOR_BTNTEXT clBtnText
General Text on Windows COLOR_WINDOWTEXT  
Active Title Bar COLOR_ACTIVECAPTION clActiveCaption
Active Window Border COLOR_ACTIVEBORDER clActiveBorder
Inactive Window Border COLOR_INACTIVEBORDER clInactiveBorder
Application Background COLOR_BACKGROUND clBackground
Desktop General COLOR_DESKTOP clBackground
Desktop Background COLOR_BACKGROUND clBackground
Inactive Title Bar Background COLOR_INACTIVECAPTION clInactiveCaption
Inactive Title Bar Text COLOR_INACTIVECAPTIONTEXT clInactiveCaptionText
Background of MDI COLOR_APPWORKSPACE clAppWorkSpace
Menu Bar   clMenuBar
Menu Background COLOR_MENU clMenu
Menu Text COLOR_MENUTEXT clMenuText
Menu Highlight   clMenuHighlight
Scrollbar COLOR_SCROLLBAR clScrollBar
Selected Items Background COLOR_HIGHLIGHT clHighlight
Selected Items Text COLOR_HIGHLIGHTTEXT clHighlightText
ToolTip Background COLOR_INFOBK clInfoBk
ToolTip Text COLOR_INFOTEXT clInfoText
Window: Text on Caption COLOR_CAPTIONTEXT clCaptionText
Window Background COLOR_WINDOW clWindow
Window Frame COLOR_WINDOWFRAME clWindowFrame
Window Text COLOR_WINDOWTEXT clWindowText
Right Side of a Gradient Active Window Title Bar COLOR_GRADIENTACTIVECAPTION clGradientActiveCaption
Right Side of a Gradient Inactive Window Title Bar COLOR_GRADIENTINACTIVECAPTION clGradientInactiveCaption
Color of Hot-Track Item (See Tree View) COLOR_HOTLIGHT clHotLight

Besides the system colors defined in the right column, the VCL provides various color names whose values are constant and can be predicted for an application. These colors are clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal, clGray, clSilver, clRed, clLime, clYellow, clBlue, clFushsia, clAqua, clLtGray, clDkGray, clWhite, clMoneyGreen, clSkyBlue, clCream, clMedGray, clNone, and clDefault. Remember that you can create any color you want by providing its red, green, and blue value then initialize a TColor variable with it.

Color Palettes

Device independence is the ability for an application to draw its intended figures, text, shapes, and display colors regardless of the device on which the drawing is performed. One way to take care of this is to manage colors at the operating system level so that Microsoft Windows can select the right color to render an object or portion of it. In some cases, a device, such as a monitor or a printer, may need to take care of the coloring details of the job(s) it is asked to perform.

A color palette is a list of colors that a device can display. For example, one device may be able to handle only two colors. Such is the case for a black and white printer. Another device could be able to use more colors than that. To control this situation, Microsoft Windows keeps track of the color palette of each device installed on the computer.

There are two types of color palettes. The default color palette is a list of colors that the operating system would use on a device unless notified otherwise. There are typically 20 reserved colors as default. A logical palette is a palette that an application creates for a specific device context.

Drawing with Colors

 

Text Drawing with Colors

The text drawing functions we used or reviewed in the previous lesson have some limited control over the text they are asked to draw. For example, they cannot specify or control the color of their text. To exercise such control, you would need other TCanvas methods or other Win32 functions.

When drawing on a device context, the TCanvas methods or Win32 functions consult the current color that has previously been selected. By default, the selected color is black for most operations, including drawing. If you want to use a different color, you must select it first. To select a color to apply when drawing text, you can call the SetTextColor() function. Its syntax is:

COLORREF SetTextColor(HDC hdc, COLORREF crColor);

This function takes as argument a color value which is crColor. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	SetTextColor(Canvas->Handle, clRed);

	Canvas->TextRect(Rect(40, 20, 120, 60), 40, 20, "Walter Bells");
}
//---------------------------------------------------------------------------

As you will learn from now on concerning the device context, once you change one of its characteristics or tool, that characteristic or tool remains in the device context until you change it again. This means that, after the SetTextColor() function has been called to change the color of text, any text drawing performed on the device context would be made using the crColor color. If you want a different color, you would have to select a new one using either SetTextColor() or some other function or a TCanvas method.

Text Background Color

If you want to highlight the text, which is equivalent to changing its background, you can call the SetBkColor() function. Its syntax is:

COLORREF SetBkColor(HDC hdc, COLORREF crColor);

You must provide the color you want to use as the crColor argument. If this function succeeds, it changes the background of the next text that would be drawn and it returns the previous background color, which you can restore at a later time. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	SetTextColor(Canvas->Handle, RGB(255, 25, 2));
	Canvas->TextOut(50, 42, "Johnny Carson");

	SetBkColor(Canvas->Handle, RGB(0, 0, 128));
	SetTextColor(Canvas->Handle, RGB(128, 255, 255));
	Canvas->TextOut(50, 60, "The once king of late-night");
}
//---------------------------------------------------------------------------

If you want to know the background color applied on the text drawn, you can call the GetBkColor() function. Its syntax is:

COLORREF GetBkColor(HDC hdc);

This function returns the color used to highlight the text, if the text is highlighted. The highlighting of text is actually controlled by the SetBkMode() function whose syntax is:

int SetBkMode(HDC hdc, int iBkMode );

This function specifies whether the background color should be applied or not. This is set by the iBkMode argument. It can have one of two values. If it is:

  • OPAQUE: the background would be drawn using the crColor value
  • TRANSPARENT: the background would not be drawn

If you want to find out what background mode is applied to the object(s) drawn, you can call the GetBkMode() function. It is declared as follows:

int GetBkMode(HDC hdc);

You can also draw text and include it in a (colored) rectangle. This can be done using the ExtTextOut() function. Its syntax is:

BOOL ExtTextOut(HDC hdc,
                int X,
                int Y,
                UINT fuOptions,
                CONST RECT *lprc,
                LPCTSTR lpString,
                UINT cbCount,
                CONST INT *lpDx);

The X and Y values specify the location of the first character of the text to be drawn.

The fuOptions parameter holds a constant that determines how the rectangle will be drawn. It can be:

  • ETO_CLIPPED: The lpString string will be clipped to the lprc rectangle. For example, the color previously specified by SetBkColor() will only highlight the text
  • ETO_GLYPH_INDEX: The lpString string refers to an array of strings from the GetCharacterPlacement() function
  • ETO_NUMERICSLATIN: The lpString value is a formatted using Latin language digits
  • ETO_NUMERICSLOCAL: The lpString string uses Regional Settings rules to format its value
  • ETO_OPAQUE: A function such as SetBkColor() would be used to fill the rectangle
  • ETO_PDY: The lpDx parameter may contain pairs of values
  • ETO_RTLREADING: For Middle-East Windows versions that read text right to left
    The lprc parameter is a rectangle that will be drawn behind the text.

The lpString string is the text to be drawn.

The cbCount value is the number of characters of lpString.

The lpDx parameter is an array of integers that specifies the amount of empty spaces that will be used between each combination of two characters. Unless you know what you are doing, pass this argument as 0, in which case the regular space used to separate characters would be used.

Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	RECT Recto = { 20, 28, 188, 128 };
	SetTextColor(Canvas->Handle, RGB(25, 55, 200));
	SetBkColor(Canvas->Handle, RGB(128, 255, 255));
	ExtTextOut(Canvas->Handle, 50, 42, ETO_OPAQUE,
			&Recto, "Johnny Carson", 13, NULL);
}
//---------------------------------------------------------------------------
 

The Color Dialog Box

 

Description of the Color Dialog Box

To provide the selection of colors on Microsoft Windows applications, the operating system provides a common dialog box appropriate for such tasks. The Color dialog box is used by various reasons to let the user set or change a color of an object such as the background color of a control or the color used to paint an object. When it displays, by default, the dialog box appears as follows:

The Color Dialog Box

This displays a constant list of colors to the user. If none of the available colors is appropriate for the task at hand, the user can click the Define Custom Colors button to expand the dialog box:

The expanded Color dialog box allows the user to either select one of the preset colors or to custom create a color by specifying its red, green, and blue values.

The user can change the color in four different areas. The top left section displays a list of 48 predefined colors. If the desired color is not in that section, the user can click and drag the mouse in the multi-colored palette. The user can also drag the right bar that displays a range based on the color of the palette; the user can scroll up and down by dragging the arrow. For more precision, the user can type the Red, Green and Blue values. Each uses a integral value that ranges from 1 to 255.

Making a Color Dialog Box Available

To provide the Color dialog box to your application, from the Dialogs tab of the Tool Palette, you can click the ColorDialog button and click anywhere on the form.

The most important and most obvious property of the Color dialog box is the selected color once the user has made a choice. When the user opens the dialog you can set the default color on the Object Inspector using the Color property. You can also set this color programmatically as follows:

//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::FormCreate(TObject *Sender)
{
	ColorDialog1->Color = clRed;
}
//---------------------------------------------------------------------------

When the user has finished using the Color dialog box and clicked OK, you can find out what color was selected by using the TColorDialog::Color property.

You can control the regular or full size of the dialog using the Options property. At design time, to manipulate the options, on the Object Inspector, click the + button on the Options field to expand it. Since the options are controlled by the TColorDialogOption is a set, you can specify as many options as you want:

//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::FormCreate(TObject *Sender)
{
	ColorDialog1->Color = clRed;
	ColorDialog1->Options << TColorDialogOption()
			      << cdFullOpen << cdAnyColor;
}
//---------------------------------------------------------------------------

If you want to supply the user with a set of colors of your choice, you can do this using a list of custom colors. To create this list, click the CustomColor field to reveal its ellipsis button, then click that button to display the String List Editor dialog box. You can specify up to 16 colors. The colors are named ColorA, ColorB, ColorC, and so on up to ColorP. To create the list, type the ordinal name and assign it an integer number. Here is an example:

String List Editor

The most important method of the Color dialog is the Execute() member function. This method occurs when the user clicks OK or presses Enter after selecting a color. You can use it to get the selected color and use it as you see fit. The following example displays a Color dialog when the user clicks a button on the form. When the user clicks OK on the Color dialog, the selected color is applied to the background of the form:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	ColorDialog1->Execute();
	Color = ColorDialog1->Color;
}
//---------------------------------------------------------------------------

The most efficient approach is to make sure that the dialog was opened and closed successfully, then retrieve the color if the user clicked OK to close the dialog. This is done through a conditional call, as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	if( ColorDialog1->Execute() )
		Color = ColorDialog1->Color;
}
//---------------------------------------------------------------------------

The TColorDialog constructor is used to dynamically create an instance of the ColorDialog control at runtime in case you cannot design it. To do this, declare a TColorDialog class in an event or function as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnCreateColorClick(TObject *Sender)
{
	TColorDialog* Dlg = new TColorDialog(this);
}
//---------------------------------------------------------------------------

After creating it, you can use it as a regular control. For example, you can change the color of an Edit control on the form as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnCreateColorClick(TObject *Sender)
{
	TColorDialog* Dlg = new TColorDialog(this);

	if( Dlg->Execute() )
		edtFullName->Color = Dlg->Color;
}
//---------------------------------------------------------------------------

To make a dynamically created Color dialog available to more than one event or function, declare an instance of the TColorDialog class in the private or public sections of the header file of a form or the unit that would use it:

Practical Learning Practical Learning: Allowing Color Changing

  1. Start a new project with the default form
  2. On the Object Inspector, click the Caption field and type Color Changer
  3. Click the Color field to reveal its combo box. Then click the arrow of the combo box and select clBackground
     
    Object Inspector
  4. Notice that the background color of the form has changed
  5. Test the application to see the result. Then close it and return to Borland C++ Builder
  6. On the Object Inspector, double-click the right field to Color to display the Color
  7. Click Define Custom Colors and set the color values to Red: 22, Green: 125, and Blue: 190
  8. Click OK and test the application. Then close it and return to Borland C++ Builder
  9. On the Object Inspector, click the Events tab and double-click the right side of the OnDblClick field
  10. Implement the event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormDblClick(TObject *Sender)
    {
    	TColorDialog *DlgColor = new TColorDialog(this);
    
    	try {
    		if( DlgColor->Execute() )
    		Color = DlgColor->Color;
    	}
    	__finally
    	{
    		delete DlgColor;
    	}
    }
    //---------------------------------------------------------------------------
  11. Test the application and double-click the form
  12. Select a color and click OK
  13. Close the form and return to Borland C++ Builder

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.

The Font Dialog Box

 

Introduction

To support easy selection of font, Microsoft Windows provides the Font dialog box:

To use the Font dialog box, the user should first have text that needs to, and can, be formatted. Users usually call the Font dialog box using a menu item or a popup menu from right clicking. Once the dialog box displays, a user can select a font by its name, its style, its size, one or both effects (Underline or Strikeout), and a color. After making the necessary changes, the user can click OK to apply the changes or click Cancel to ignore the selected attributes.

Allowing Font Formatting

VCL applications can provide the Font dialog box through the TFontDialog class. To make it available, at design time, from the Dialogs tab of the Tool Palette, you can click FontDialog and click on the form.

If you cannot add a FontDialog object at design time for any reason, you can get a Font dialog box by declaring a pointer to TFontDialog. This is can be done in the function or event where the dialog box would be needed. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	TFontDialog *dlgFont = new TFontDialog(Form1);
}
//---------------------------------------------------------------------------

If you want the dialog box to be available to all functions and events of a unit, you can declare a pointer to a TFontDialog class in the class of the form where the object would be needed.

At design time, the Font dialog box hardly needs any change of properties to work. The only time you would set its properties is if you judge that its default properties are not conform to your particular scenario. For example, if you are providing font formatting for a RichEdit control and you want users to control the font characteristics of individual letters or paragraph, there should be nothing to change at design time. Otherwise, the default properties can be changed using the Object Inspector.

The Object Inspector presents the same options the user would need to set when displaying the Font dialog box. Imagine that you want to change the default font attributes of any control that descends from the TControl class, for example a memo. At design time, when the object is selected on the form, on the Object Inspector, you can expand the Font property and the Style set if necessary then change the properties as you see fit:

At run time, you can still set the characteristics as you wish. For example, you can change them in response to some intermediate action. On the other hand, you can use the TFontDialog object to let the user customize the font characteristics of text.

Once, and however, you have a TFontDialog instance, you can display the Font dialog box by calling the Execute() method. The font dialog box is equipped with two primary buttons: OK and Cancel. After using it, if the user clicks OK, this implies that if there were changes of font, size, color, etc, the user wants them committed to the document. If the user clicks Cancel, this means that you should ignore any actions that were performed on the dialog box. The Execute() method is Boolean. It returns true if the user clicks OK. Otherwise, if the user clicks Cancel, it would return false. Therefore, after the user has used it, you should find out if she clicked OK or Cancel before applying her changes. This inquiry is usually performed with an if conditional statement as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	if( dlgFont->Execute() )
	{
		// What to do if the user clicked OK
	}
}
//---------------------------------------------------------------------------

The Name of the selected font is an AnsiString value that indirectly belongs to the TFont class. After the user has clicked OK, you can find out what font was selected and assign it to the Font object you are trying to change. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	if( dlgFont->Execute() )
	{
		Memo1->Font->Name = dlgFont->Font->Name;
	}
}
//---------------------------------------------------------------------------

The styles can be managed using the Font dialog box as one object. After the user has clicked OK on the dialog box, you can simply assign whatever style was set to the TFont::Style property of the object that needs the change. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	if( dlgFont->Execute() )
	{
		Memo1->Font->Name  = dlgFont->Font->Name;
		Memo1->Font->Size  = dlgFont->Font->Size;
		Memo1->Font->Color = dlgFont->Font->Color;
		Memo1->Font->Style = dlgFont->Font->Style;
	}
}
//---------------------------------------------------------------------------

 

 
Previous Copyright © 2005-2007 Yevol Next