GDI Accessories: Colors





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:

7 6 5 4 3 2 1 0
7 6 5 4 3 2 1 0
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)
	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
3D Objects: Top and Left Edges COLOR_3DHILIGHT
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
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);
Home Copyright © 2005-2012, FunctionX, Inc.