📄 ch06.htm
字号:
<TD>
<P>0.1 millimeter</P>
<TR>
<TD>
<P>MM_TEXT</P>
<TD>
<P>Device pixel</P>
<TR>
<TD>
<P>MM_TWIPS</P>
<TD>
<P>1/1440 inch</P></TABLE>
<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:
they are <font color="#008000">FW_DONTCARE</font>, <font color="#008000">FW_THIN</font>, <font color="#008000">FW_EXTRALIGHT</font>, <font color="#008000">FW_ULTRALIGHT</font>, <font color="#008000">FW_LIGHT</font>, <font color="#008000">FW_NORMAL</font>,
<font color="#008000">FW_REGULAR</font>, <font color="#008000">FW_MEDIUM</font>, <font color="#008000">FW_SEMIBOLD</font>, <font color="#008000">FW_DEMIBOLD</font>, <font color="#008000">FW_BOLD</font>, <font color="#008000">FW_EXTRABOLD</font>, <font
color="#008000">FW_ULTRABOLD</font>, <font color="#008000">FW_BLACK</font>, and <font color="#008000">FW_HEAVY</font>. Not all fonts are available in all weights. There are four character sets available (<font color="#008000">ANSI_CHARSET</font>, <font
color="#008000">OEM_CHARSET</font>, <font color="#008000">SYMBOL_CHARSET</font>, and <font color="#008000">UNICODE_CHARSET</font>) but for writing English text you will almost always use <font color="#008000">ANSI_CHARSET</font>. (Unicode is discussed in
<A HREF="index28.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index28.htm" target="text">Chapter 28</A>, "Future Explorations.") The last field in the <font color="#008000">LOGFONT</font> structure is the face name, such as Courier or Helvetica.</P>
<P>Listing 6.4 shows the code you need to add to the empty <font color="#008000">ShowFonts()</font> function you created earlier.</P>
<P><I>Listing 6.4—CPaint1View::ShowFonts()</I></P>
<pre><font color="#008000">void CPaint1View::ShowFonts(CDC * pDC)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> // Initialize a LOGFONT structure for the fonts.</font></pre>
<pre><font color="#008000"> LOGFONT logFont;</font></pre>
<pre><font color="#008000"> logFont.lfHeight = 8;</font></pre>
<pre><font color="#008000"> logFont.lfWidth = 0;</font></pre>
<pre><font color="#008000"> logFont.lfEscapement = 0;</font></pre>
<pre><font color="#008000"> logFont.lfOrientation = 0;</font></pre>
<pre><font color="#008000"> logFont.lfWeight = FW_NORMAL;</font></pre>
<pre><font color="#008000"> logFont.lfItalic = 0;</font></pre>
<pre><font color="#008000"> logFont.lfUnderline = 0;</font></pre>
<pre><font color="#008000"> logFont.lfStrikeOut = 0;</font></pre>
<pre><font color="#008000"> logFont.lfCharSet = ANSI_CHARSET;</font></pre>
<pre><font color="#008000"> logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;</font></pre>
<pre><font color="#008000"> logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;</font></pre>
<pre><font color="#008000"> logFont.lfQuality = PROOF_QUALITY;</font></pre>
<pre><font color="#008000"> logFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;</font></pre>
<pre><font color="#008000"> strcpy(logFont.lfFaceName, "Times New Roman");</font></pre>
<pre><font color="#008000"> // Initialize the position of text in the window.</font></pre>
<pre><font color="#008000"> UINT position = 0;</font></pre>
<pre><font color="#008000"> // Create and display eight example fonts.</font></pre>
<pre><font color="#008000"> for (UINT x=0; x<8; ++x)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> // Set the new font's height.</font></pre>
<pre><font color="#008000"> logFont.lfHeight = 16 + (x * 8);</font></pre>
<pre><font color="#008000"> // Create a new font and select it into the DC.</font></pre>
<pre><font color="#008000"> CFont font;</font></pre>
<pre><font color="#008000"> font.CreateFontIndirect(&logFont);</font></pre>
<pre><font color="#008000"> CFont* oldFont = pDC->SelectObject(&font);</font></pre>
<pre><font color="#008000"> // Print text with the new font.</font></pre>
<pre><font color="#008000"> position += logFont.lfHeight;</font></pre>
<pre><font color="#008000"> pDC->TextOut(20, position, "A sample font.");</font></pre>
<pre><font color="#008000"> // Restore the old font to the DC.</font></pre>
<pre><font color="#008000"> pDC->SelectObject(oldFont);</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000">}</font></pre>
<p><font color="#008000">ShowFonts()</font> starts by setting up a Times Roman font eight pixels high, with a width that best matches the height, and all other attributes set to normal defaults.</P>
<P>In order to show the many fonts that are displayed in its window, the Paint1 application creates its fonts in a <font color="#008000">for</font> loop, modifying the value of the <font color="#008000">LOGFONT</font> structure's <font
color="#008000">lfHeight</font> member each time through the loop, using the loop variable, <font color="#008000">x</font>, to calculate the new font height, like this:</P>
<pre><font color="#008000">logFont.lfHeight = 16 + (x * 8);</font></pre>
<P>Because <font color="#008000">x</font> 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 eight pixels higher than the previous one.</P>
<P>After setting the font's height, the program creates a <font color="#008000">CFont</font> object and calls its <font color="#008000">CreateFontIndirect() function</font>, which attempts to create a CFont object corresponding to the <font
color="#008000">LOGFONT</font> you created. It will change the <font color="#008000">LOGFONT</font> to describe the CFont that was actually created, given the fonts that are installed on the user’s machine.</P>
<P>After <font color="#008000">ShowFonts()</font> calls CreateFontIndirect(), the <font color="#008000">CFont</font> object has been 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 cannot 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 are finished. The same function, SelectObject() is used to select a variety of bojects into a device context: the font you are 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 on the screen. The local variable <font color="#008000">position</font> holds the vertical position in the window at which the next line of text should be printed. This
position depends upon the height of the current font. After all, if there's not enough space between the lines, the larger fonts will overlap the smaller ones. When Windows created the new font, it stored the font's height (which is most likely the height
that you requested, but might not be) in the <font color="#008000">LOGFONT</font> structure's <font color="#008000">lfHeight</font> member. By adding the value stored in <font color="#008000">lfHeight</font>, the program can determine the next position at
which to display the line of text. To make the text appear on the screen, <font color="#008000">ShowFonts()</font> calls <font color="#008000">TextOut()</font>.</P>
<p><font color="#008000">TextOut()</font>'s first two arguments are the X and Y coordinates at which to print the text. The third argument is the text to print. Having printed the text, you restore the old font to the DC in case this is the last time
through the loop.</P>
<P>Build the application and run it. It should look something like Figure 6.3. If you click the window it will go blank, because the <font color="#008000">ShowPens()</font> routine doesn’t draw anything. Click again and it is still blank, this time
because the <font color="#008000">ShowBrushes()</font> routine doesn’t draw anything. Click a third time and you are back to the fonts screen.</P>
<A HREF="Hfig03.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch06/Hfig03.gif"><b>Fig. 6.3</b></A>
<P><I>The font display shows how you can create different types of text </I><I>output.</I></P>
<P><B>Sizing and Positioning the Window</B></P>
<P>As you can see in Figure 6.3, Paint1 does not display eight different fonts: only seven can fit in the window. To correct this, you need to set the size of the window a little larger than the Windows default. In an MFC program, you do this in the
mainframe class <font color="#008000">PreCreateWindow()</font> function. This is called for you just before the mainframe window is created. The mainframe window surrounds the entire application and governs the size of the view.</P>
<p><font color="#008000">PreCreateWindow()</font> takes one parameter, a reference to a <font color="#008000">CREATESTRUCT</font> structure. The <font color="#008000">CREATESTRUCT</font> structure contains essential information about the window that is
about to be created, as shown in Listing 6.5.</P>
<P><I>Listing 6.5—The </I>CREATESTRUCT<I> Structure</I></P>
<pre><font color="#008000">typedef struct tagCREATESTRUCT {</font></pre>
<pre><font color="#008000"> LPVOID lpCreateParams;</font></pre>
<pre><font color="#008000"> HANDLE hInstance;</font></pre>
<pre><font color="#008000"> HMENU hMenu;</font></pre>
<pre><font color="#008000"> HWND hwndParent;</font></pre>
<pre><font color="#008000"> int cy;</font></pre>
<pre><font color="#008000"> int cx;</font></pre>
<pre><font color="#008000"> int y;</font></pre>
<pre><font color="#008000"> int x;</font></pre>
<pre><font color="#008000"> LONG style;</font></pre>
<pre><font color="#008000"> LPCSTR lpszName;</font></pre>
<pre><font color="#008000"> LPCSTR lpszClass;</font></pre>
<pre><font color="#008000"> DWORD dwExStyle;</font></pre>
<pre><font color="#008000">} CREATESTRUCT;</font></pre>
<P>If you've programmed Windows without application frameworks like MFC, you'll recognize the information stored in the <font color="#008000">CREATESTRUCT</font> structure. You used to supply much of this information when calling the Windows API function
<font color="#008000">CreateWindow()</font> to create your application's window. Of special interest to MFC programmers are the <font color="#008000">cx</font>, <font color="#008000">cy</font>, <font color="#008000">x</font>, and <font
color="#008000">y</font> members of this structure. By changing <font color="#008000">cx</font> and <font color="#008000">cy</font>, you can set the width and height, respectively, of the window. Similarly, modifying <font color="#008000">x</font> and
<font color="#008000">y</font> changes the window's position. By overriding <font color="#008000">PreCreateWindow()</font>, you get a chance to fiddle with the <font color="#008000">CREATESTRUCT</font> structure before Windows uses it to create the
window.</P>
<P>AppWizard created a <font color="#008000">CMainFrame::PreCreateWindow()</font> function. Expand <font color="#008000">CMainFrame</font> in ClassView, double-click <font color="#008000">PreCreateWindow()</font> to edit it, and add the code shown in
Listing 6.6. This sets the height and width of the application. It also prevents the user from resizing the application, by using the bitwise and operator, <font color="#008000">&</font>, to turn off the <font color="#008000">WS_SIZEBOX</font> style
bit. Now the user cannot resize the application.</P>
<P><I>Listing 6.6—CMainFrame::PreCreateWindow()</I></P>
<pre><font color="#008000">BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> cs.cx = 440;</font></pre>
<pre><font color="#008000"> cs.cy = 480;</font></pre>
<pre><font color="#008000"> cs.style &= ~WS_SIZEBOX;</font></pre>
<pre><font color="#008000"> return CFrameWnd::PreCreateWindow(cs);</font></pre>
<pre><font color="#008000">}</font></pre>
<P>It's important that, after your own code in <font color="#008000">PreCreateWindow()</font>, you call the base class's PreCreateWindow()<font color="#008000">. </font>Failure to do this will leave you without a valid window, because MFC never gets a
chance to pass the <font color="#008000">CREATESTRUCT</font> structure on to Windows, and so Windows never creates your window. When overriding class member functions, you usually need to call the base class's version.</P>
<P>Build and run Paint1 to confirm that all eight fonts fit in the application’s window. Now you are ready to demonstrate pens.</P>
<P><B>Using Pens</B></P>
<P>You'll be pleased to know that pens are much easier to deal with than fonts, mostly because you don't have to fool around with complicated data structures like <font color="#008000">LOGFONT</font>. In fact, to create a pen, you need only supply the
pen's line style, thickness, and color. The Paint1 application's <font color="#008000">ShowPens()</font> function displays in its window lines drawn using different pens created within a <font color="#008000">for</font> loop. The code is shown in Listing
6.7.</P>
<P><I>Listing 6.7—CPaint1View::ShowPens()</I></P>
<pre><font color="#008000">void CPaint1View::ShowPens(CDC * pDC)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> // Initialize the line position.</font></pre>
<pre><font color="#008000"> UINT position = 10;</font></pre>
<pre><font color="#008000"> // Draw sixteen lines in the window.</font></pre>
<pre><font color="#008000"> for (UINT x=0; x<16; ++x)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> // Create a new pen and select it into the DC.</font></pre>
<pre><font color="#008000">CPen pen(PS_SOLID, x*2+1, RGB(0, 0, 255));</font></pre>
<pre><font color="#008000"> CPen* oldPen = pDC->SelectObject(&pen);</font></pre>
<pre><font color="#008000"> // Draw a line with the new pen.</font></pre>
<pre><font color="#008000"> position += x * 2 + 10;</font></pre>
<pre><font color="#008000"> pDC->MoveTo(20, position);</font></pre>
<pre><font color="#008000"> pDC->LineTo(400, position);</font></pre>
<pre><font color="#008000"> // Restore the old pen to the DC.</font></pre>
<pre><font color="#008000"> pDC->SelectObject(oldPen);</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000">}</font></pre>
<P>Within the loop, <font color="#008000">ShowPens()</font> first creates a custom pen. The constructor takes three parameters. The first is the line's style, one of the styles listed in Table 6.3. (Only solid lines can be drawn with different
thicknesses. Patterned lines always have a thickness of 1.) The second argument is the line thickness, which increases each time through the loop. The third argument is the line's color. The <font color="#008000">RGB</font> macro takes three values for the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -