GDI
Accessories and Tools: Fonts, CFont, LOGFONT, GetLogFont, CreateFontIndirect, CreateFont
|
|
MFC,
VC++ Source Code
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.
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();
ASSERT_VALID(pDoc);
CFont font;
font.CreatePointFont(920, "Garamond");
CFont *pFont = pDC->SelectObject(&font);
pDC->TextOut(20, 18, "Christine", 9);
pDC->SelectObject(pFont);
font.DeleteObject();
}
|
|
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();
ASSERT_VALID(pDoc);
CFont font;
font.CreatePointFont(920, "Garamond");
CFont *pFont = pDC->SelectObject(&font);
pDC->SetTextColor(RGB(0, 125, 250));
pDC->TextOut(20, 18, "Christine", 9);
pDC->SelectObject(pFont);
font.DeleteObject();
}
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();
ASSERT_VALID(pDoc);
CFont font;
font.CreatePointFont(920, "Garamond");
CFont *pFont = pDC->SelectObject(&font);
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(110, 185, 250));
pDC->TextOut(26, 24, "Christine", 9);
pDC->SetTextColor(RGB(0, 0, 255));
pDC->TextOut(20, 18, "Christine", 9);
pDC->SelectObject(pFont);
font.DeleteObject();
}
|
|
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 |
|
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
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 |
|
ANSI_CHARSET |
0 |
|
DEFAULT_CHARSET |
1 |
|
SYMBOL_CHARSET |
2 |
|
SHIFTJIS_CHARSET |
128 |
|
OEM_CHARSET |
255 |
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_Mucancode.net, 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,
FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_ROMAN, "Times New Roman");
CFont *pFont = pDC->SelectObject(&font);
pDC->TextOut(20, 128, "Euzhan Palcy", 12);
pDC->SelectObject(pFont);
font.DeleteObject();
}
|
|
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;
TCHAR lfFaceName[LF_FACESIZE];
} LOGFONT, *PLOGFONT;
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 LogFont;
LogFont.lfStrikeOut = 0;
LogFont.lfUnderline = 0;
LogFont.lfHeight = 42;
LogFont.lfEscapement = 0;
LogFont.lfItalic = TRUE;
font.CreateFontIndirect(&LogFont);
CFont *pFont = pDC->SelectObject(&font);
pDC->TextOut(20, 18, "James Kolowski", 14);
pDC->SelectObject(pFont);
font.DeleteObject();
}
|
|
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;
LOGFONT LogFont;
font = this->GetFont();
font->GetLogFont(&LogFont);
char StrFont[40];
strcpy(StrFont, LogFont.lfFaceName);
CClientDC dc(this);
dc.TextOut(58, 120, StrFont, strlen(StrFont));
}
|