📄 ch05.htm
字号:
<P>This initializes the display selector to the font demonstration. You use the display
selector in the OnDraw() function called by CView::OnPaint(). AppWizard has created
CPaint1View::OnDraw(), but it doesn't do anything at the moment. Double-click the
function name in ClassView and add the code in Listing 5.2 to the function, removing
the TODO comment left by AppWizard.</P>
<P>
<H4>Listing 5.2  CPaint1View::OnDraw()</H4>
<PRE>void CPaint1View::OnDraw(CDC* pDC)
{
CPaint1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
switch (m_Display)
{
case Fonts:
ShowFonts(pDC);
break;
case Pens:
ShowPens(pDC);
break;
case Brushes:
ShowBrushes(pDC);
break;
}
</PRE>
<PRE>}
</PRE>
<P>You will write the three functions ShowFonts(), ShowPens(), and ShowBrushes()
in upcoming sections of this chapter. Each function uses the same DC pointer that
was passed to OnDraw() by OnPaint(). Add them to the class now by following these
steps:</P>
<DL>
<DT></DT>
<DD><B>1. </B>Right-click the CPaint1View class in ClassView and select Add Member
Function.
<P>
<DT></DT>
<DD><B>2. </B>Enter <B>void</B> for the Function Type.
<P>
<DT></DT>
<DD><B>3. </B>Enter <B>ShowFonts(CDC* pDC)</B> for the Function Declaration.
<P>
<DT></DT>
<DD><B>4. </B>Change the access to protected. Click OK.
<P>
<DT></DT>
<DD><B>5. </B>Repeat steps 1 through 4 for ShowPens(CDC* pDC) and ShowBrushes(CDC*
pDC).
<P>
</DL>
<P>The last step in arranging for the display to switch is to catch left mouse clicks
and write code in the message handler to change m_display.</P>
<P>Right-click CPaint1View in the ClassView and select Add Windows Message Handler
from the shortcut menu that appears. Double-click WM_LBUTTONDOWN in the New Windows
Messages/Events list box. ClassWizard adds a function called OnLButtonDown() to the
view and adds entries to the message map so that this function will be called whenever
users click the left mouse button over this view.</P>
<P>Click Edit Existing to edit the OnLButtonDown() you just created, and add the
code shown in Listing 5.3.</P>
<P>
<H4>Listing 5.3  CPaint1View::OnLButtonDown()</H4>
<PRE>void CPaint1View::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_Display == Fonts)
m_Display = Pens;
else if (m_Display == Pens)
m_Display = Brushes;
else
m_Display = Fonts
Invalidate();
CView::OnLButtonDown(nFlags, point);
</PRE>
<PRE>}
</PRE>
<P>As you can see, depending on its current value, m_display is set to the next display
type in the series. Of course, just changing the value of m_display doesn't accomplish
much; the program still needs to redraw the contents of its window. The call to Invalidate()
tells Windows that all of the window needs to be repainted. This causes Windows to
generate a WM_PAINT message for the window, which means that eventually OnDraw()
will be called and the view will be redrawn as a font, pen, or brush demonstration.</P>
<P>
<H3><A NAME="Heading6"></A>Using Fonts</H3>
<P>Changing the font used in a view is a technique you'll want to use in various
situations. It's not as simple as you might think because you can never be sure that
any given font is actually installed on the user's machine. You set up a structure
that holds information about the font you want, attempt to create it, and then work
with the font you actually have, which might not be the font you asked for.</P>
<P>A Windows font is described in the LOGFONT structure outlined in Table 5.1. The
LOGFONT structure uses 14 fields to hold a complete description of the font. Many
fields can be set to 0 or the default values, depending on the program's needs.</P>
<P>
<H4>Table 5.1  LOGFONT Fields and Their Descriptions</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"><B>Field</B></TD>
<TD ALIGN="LEFT"><B>Description</B></TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfHeight</TD>
<TD ALIGN="LEFT">Font height in logical units</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfWidth</TD>
<TD ALIGN="LEFT">Font width in logical units</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfEscapement</TD>
<TD ALIGN="LEFT">Angle at which to draw the text</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfOrientation</TD>
<TD ALIGN="LEFT">Character tilt in tenths of a degree</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfWeight</TD>
<TD ALIGN="LEFT">Font weight</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfItalic</TD>
<TD ALIGN="LEFT">A nonzero value indicates italics</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfUnderline</TD>
<TD ALIGN="LEFT">A nonzero value indicates an underlined font</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfStrikeOut</TD>
<TD ALIGN="LEFT">A nonzero value indicates a strikethrough font</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfCharSet</TD>
<TD ALIGN="LEFT">Font character set</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfOutPrecision</TD>
<TD ALIGN="LEFT">How to match requested font to actual font</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfClipPrecision</TD>
<TD ALIGN="LEFT">How to clip characters that run over clip area</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfQuality</TD>
<TD ALIGN="LEFT">Print quality of the font</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfPitchAndFamily</TD>
<TD ALIGN="LEFT">Pitch and font family</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">lfFaceName</TD>
<TD ALIGN="LEFT">Typeface name</TD>
</TR>
</TABLE>
</P>
<P>Some terms in Table 5.1 need a little explanation. The first is <I>logical units</I>.
How high is a font with a height of 8 logical units, for example? The meaning of
a logical unit depends on the <I>mapping mode</I> you're using, as shown in Table
5.2. The default mapping mode is MM_TEXT, which means that one logical unit is equal
to 1 pixel. Mapping modes are discussed in more detail in Chapter 6.</P>
<P>
<H4>Table 5.2  Mapping Modes</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"><B>Mode</B></TD>
<TD ALIGN="LEFT"><B>Unit</B></TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">MM_HIENGLISH</TD>
<TD ALIGN="LEFT">0.001 inch</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">MM_HIMETRIC</TD>
<TD ALIGN="LEFT">0.01 millimeter</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">MM_ISOTROPIC</TD>
<TD ALIGN="LEFT">Arbitrary</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">MM_LOENGLISH</TD>
<TD ALIGN="LEFT">0.01 inch</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">MM_LOMETRIC</TD>
<TD ALIGN="LEFT">0.1 millimeter</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">MM_TEXT</TD>
<TD ALIGN="LEFT">Device pixel</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">MM_TWIPS</TD>
<TD ALIGN="LEFT">1/1440 inch</TD>
</TR>
</TABLE>
</P>
<P><I>Escapement</I> refers to writing text along an angled line. <I>Orientation</I>
refers to writing angled text along a flat line. The font weight refers to the thickness
of the letters. A number of constants have been defined for use in this field: FW_DONTCARE,
FW_THIN, FW_EXTRALIGHT, FW_ULTRALIGHT, FW_LIGHT, FW_NORMAL, FW_REGULAR, FW_MEDIUM,
FW_SEMIBOLD, FW_DEMIBOLD, FW_BOLD, FW_EXTRABOLD, FW_ULTRABOLD, FW_BLACK, and FW_HEAVY.
Not all fonts are available in all weights. Four character sets are available (ANSI_CHARSET,
OEM_CHARSET, SYMBOL_CHARSET, and UNICODE_CHARSET), but for writing English text you'll
almost always use ANSI_CHARSET. (Unicode is discussed in Chapter 28, "Future
Explorations.") The last field in the LOGFONT structure is the face name, such
as Courier or Helvetica.</P>
<P>Listing 5.4 shows the code you need to add to the empty ShowFonts() function you
created earlier.</P>
<P>
<H4>Listing 5.4  CPaint1View::ShowFonts()</H4>
<PRE>void CPaint1View::ShowFonts(CDC * pDC)
{
// Initialize a LOGFONT structure for the fonts.
LOGFONT logFont;
logFont.lfHeight = 8;
logFont.lfWidth = 0;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = 0;
logFont.lfUnderline = 0;
logFont.lfStrikeOut = 0;
logFont.lfCharSet = ANSI_CHARSET;
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = PROOF_QUALITY;
logFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
strcpy(logFont.lfFaceName, "Times New Roman");
// Initialize the position of text in the window.
UINT position = 0;
// Create and display eight example fonts.
for (UINT x=0; x<8; ++x)
{
// Set the new font's height.
logFont.lfHeight = 16 + (x * 8);
// Create a new font and select it into the DC.
CFont font;
font.CreateFontIndirect(&logFont);
CFont* oldFont = pDC->SelectObject(&font);
// Print text with the new font.
position += logFont.lfHeight;
pDC->TextOut(20, position, "A sample font.");
// Restore the old font to the DC.
pDC->SelectObject(oldFont);
}
</PRE>
<PRE>}
</PRE>
<P>ShowFonts()starts by setting up a Times Roman font 8 pixels high, with a width
that best matches the height and all other attributes set to normal defaults.</P>
<P>To show the many fonts displayed in its window, the Paint1 application creates
its fonts in a for loop, modifying the value of the LOGFONT structure's lfHeight
member each time through the loop, using the loop variable x to calculate the new
font height:</P>
<P>
<PRE>logFont.lfHeight = 16 + (x * 8);
</PRE>
<P>Because x starts at 0, the first font created in the loop will be 16 pixels high.
Each time through the loop, the new font will be 8 pixels higher than the previous
one.</P>
<P>After setting the font's height, the program creates a CFont object and calls
its CreateFontIndirect() function, which attempts to create a CFont object corresponding
to the LOGFONT you created. It will change the LOGFONT to describe the CFont that
was actually created, given the fonts installed on the user's machine.</P>
<P>After ShowFonts() calls CreateFontIndirect(), the CFont object is associated with
a Windows font. Now you can select it into the DC. Selecting objects into device
contexts is a crucial concept in Windows output programming. You can't use any graphical
object, such as a font, directly; instead, you select it into the DC and then use
the DC. You always save a pointer to the old object that was in the DC (the pointer
is returned from the SelectObject() call) and use it to restore the device context
by selecting the old object again when you're finished. The same function, SelectObject(),
is used to select various objects into a device context: the font you're using in
this section, a pen, a brush, or a number of other drawing objects.</P>
<P>After selecting the new font into the DC, you can use the font to draw text onscreen.
The local variable position holds the vertical position in the window at which the
next line of text should be printed. This position depends on the height of the current
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -