📄 ch12.htm
字号:
Bitmap := TBitmap.Create; Bitmap.LoadFromFile(`handshak.bmp'); Rgn := CreateRectRgn(50, 50, 250, 250); SelectClipRgn(Canvas.Handle, Rgn); Canvas.Draw(0, 0, Bitmap); Bitmap.Free;end;</PRE><P>Now when you run the program you will see that only a portion of the bitmap isdisplayed. The SelectClipRgn function sets the canvas' clipping region to the rectangleidentified by the coordinates 50, 50, 250, and 250. The bitmap is still being drawnin the same location it was before, yet now only a portion of the bitmap (definedby the clipping region) can be seen. Everything outside the clipping region is ignored.</P><P>Regions don't have to be rectangular. Let's take the previous example and makeit more interesting. Remove the line that creates the rectangular region and replaceit with this line:</P><P><PRE>Rgn := CreateEllipticRgn(30, 30, 170, 170);</PRE><PRE>Now run the program again. This time, the bitmap is limited to a circular region. Figure 12.5 shows the program with the elliptical region in place.</PRE><P><A HREF="javascript:popUp('28671205.gif')"><B>FIGURE 12.5.</B></A><B> </B><I>Anelliptical clipping region.</I></P><P>Let's try another type of region. Again, remove the line that defines the regionand replace it with these lines:</P><P><PRE>const Points : array[0..3] of TPoint = ((X:80;Y:0), (X:0;Y:80), (X:80;Y:160), (X:160;Y:80));var Bitmap : TBitmap; Rgn : HRGN;begin Bitmap := TBitmap.Create; Bitmap.LoadFromFile(`handshak.bmp'); Rgn := CreatePolygonRgn(Points, 4, ALTERNATE); SelectClipRgn(Canvas.Handle, Rgn); Canvas.Draw(0, 0, Bitmap); Bitmap.Free;end;</PRE><P>This time you are using a polygon region. The points array defines the pointsthat create the region. The CreatePolygonRgn function creates a region from a seriesof points. You can use as many points as you want. You don't even have to specifythe closing point because the region is automatically closed between the first pointand the last point. Run the program again and see what you get. Figure 12.6 showsthe results of this exercise.</P><P><A HREF="javascript:popUp('28671206.gif')"><B>FIGURE 12.6.</B></A><B> </B><I>Apolygon clipping region.</I></P><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> This code snippet also shows how to initialize a const array of records. Here's the code I'm referring to:</P> <PRE>const Points : array[0..3] of TPoint = ((X:80;Y:0), (X:0;Y:80), (X:80;Y:160), (X:160;Y:80));</PRE></BLOCKQUOTE><PRE></PRE><BLOCKQUOTE> <P>This code declares an array of TPoint records and initializes it with data. TPoint has two fields: X and Y. Notice that the field name is listed, followed by a colon and the value to be assigned to that field (X:80, for example). Notice also that both the X and Y fields are assigned values and those values are paired with parentheses. This is done four times because the array has four elements. This is the only way to declare and initialize a const array of records. <HR></BLOCKQUOTE><P>Regions can be very useful when you are doing certain kinds of drawing operations.You might not need to use clipping regions often, but when you need them, they areinvaluable.</P><P><H2>Basic Drawing Operations</H2><P>You have already encountered some of the basic graphics routines as you have workedthrough the book. By now you know that the Rectangle method is used to draw squaresand rectangles, the Ellipse method is used to draw circles and ovals, and that theMoveTo and LineTo methods are used to draw lines.</P><P>There is also the Arc method for drawing arcs and the Pie method for drawing pie-shapedobjects. All in all, it's fairly basic. There's not much point in going into a lotof detail on the methods of TCanvas. Instead, let's move on to the more interesting(and troublesome) graphics operations you are likely to encounter when writing Delphiapplications.</P><P><H3><A NAME="Heading7"></A>Drawing Text</H3><P>Drawing text doesn't sound like it should be too difficult, does it? The truthis that there are several little pitfalls that, if you aren't aware of them, canmake drawing text a difficult experience. In addition, there are several nice textdrawing features that you should know about.</P><P><H4>The TextOut and TextRect Methods</H4><P>The TextOut method is the most basic way to draw text on a canvas. There reallyisn't too much to say about TextOut. You just pass it the X position, the Y position,and the text to display--for example,</P><P><PRE>Canvas.TextOut(20, 20, `Joshua Reisdorph');</PRE><P>This code displays the given string at position 20, 20 on the form. The X andY coordinates specify the top left corner of the text to be drawn, not the baseline.To illustrate what I mean, test this code:</P><P><PRE>Canvas.TextOut(20, 20, `This is a test.');Canvas.MoveTo(20, 20);Canvas.LineTo(100, 20);</PRE><P>This code displays some text at position 20, 20 and then draws a line from thatsame position to position 100, 20. Figure 12.7 shows the results of this code. Noticethat the line is drawn across the top of the text.</P><P><A HREF="javascript:popUp('28671207.gif')"><B>FIGURE 12.7.</B></A><B> </B><I>Textdrawn with TextOut.</I></P><P>Use TextOut whenever you have text to display that doesn't need a lot of finepositioning.</P><P>The TextRect method enables you to specify a clipping rectangle in addition tothe text to be displayed. Use this method when the text needs to be constrained withincertain boundaries. Any of the text that falls outside the boundary will be clipped.The following code snippet ensures that no more than 100 pixels of the text willbe displayed:</P><P><PRE>Canvas.TextRect(Rect(20, 50, 120, 70), 20, 50, `This is a very long line that might get clipped.');</PRE><PRE>Both TextOut and TextRect can only draw single lines of text. No wrapping of the text is performed.</PRE><BLOCKQUOTE> <P><HR><strong>TIP:</strong> To draw text with tab stops, see the Windows API function TabbedTextOut. <HR></BLOCKQUOTE><H4>Text Backgrounds</H4><P>Refer to Figure 12.7. Notice that the text has a white background--not very appealingon a gray form. The text background is obtained from the current brush (white bydefault). To remedy the unsightly results of Figure 12.7, you need to take one oftwo actions: Either change the color of the canvas brush, or make the text's backgroundtransparent.</P><P>Changing the background color of the text is fairly easy. The question is, doyou know what color to make the text's background? In this case, the text's backgroundcan be the same color as the form, so you can do this:</P><P><PRE>Canvas.Brush.Color := Color;</PRE><P>This code will work for most situations, but in some cases you need more control.It would be easier if you could just make the background of the text transparent.The good news is, you can. Here's how the code would look:</P><P><PRE>var OldStyle : TBrushStyle;begin OldStyle := Canvas.Brush.Style; Canvas.Brush.Style := bsClear; Canvas.TextOut(20, 20, `This is a test.'); Canvas.Brush.Style := OldStyle;end;</PRE><PRE>First, save the current brush style. Next, set the brush style to transparent (bsClear). After you display the text, set the brush style back to what it was before. You should get into the habit of saving the previous style and resetting it when you are done drawing the text. It is unlikely that you'll want to leave the brush style set to transparent, so resetting the previous style is always a good idea.</PRE><P>Using a transparent background has other advantages as well. Let's say you wantto display some text over a bitmap background. In that case you can't use a solidbackground. Here's a code snippet that illustrates the point (the FACTORY.BMP filecan be found in your Borland Shared Files56Color directory):</P><P><PRE>var OldStyle : TBrushStyle; Bitmap : TBitmap;begin Bitmap := TBitmap.Create; Bitmap.LoadFromFile(`factory.bmp'); Canvas.Draw(0, 0, Bitmap); Canvas.Font.Name := `Arial Bold'; Canvas.Font.Size := 13; OldStyle := Canvas.Brush.Style; Canvas.Brush.Style := bsClear; Canvas.TextOut(20, 5, `Transparent Background'); Canvas.Brush.Style := OldStyle; Canvas.TextOut(20, 30, `Solid Background'); Bitmap.Free;end;</PRE><P>This code draws a bitmap on the form. Next, text is drawn on the form (over thebitmap) with a transparent background. After that, more text is drawn with the regularbackground. Figure 12.8 shows the results of this code. As you can see, making thebackground transparent creates a much more appealing image.</P><P><A HREF="javascript:popUp('28671208.gif')"><B>FIGURE 12.8.</B></A><B> </B><I>Textdrawn over a bitmap with transparent and solid backgrounds.</I></P><P>Another reason for using transparent backgrounds for text is illustrated on Day13 in the section, "Owner-Drawn Status Panels." There you give the statusbar text a 3D look by drawing the text once in white and drawing it again, slightlyoffset, in black. The only way that code works is by using a transparent background.As you can see, sometimes a transparent background is the only option for achievingthe effect you are looking for.</P><P><H4>The DrawText Function</H4><P>The Windows API DrawText function gives you much greater control over text thatis drawn on the canvas than does TextOut. For some reason, the TCanvas class doesnot have a DrawText method. To use DrawText, then, means using the API directly.First, let's look at a basic DrawText example and then I'll tell you more about thepower of this function:</P><P><PRE>var R : TRect;begin R := Rect(20, 20, 220, 80); Canvas.Rectangle(20,20, 220, 80); DrawText(Canvas.Handle, `An example of DrawText.', -1, R, DT_SINGLELINE or DT_VCENTER or DT_CENTER);end;</PRE><P>Figure 12.9 shows the results of this code as well as results from the followingexamples.</P><P><A HREF="javascript:popUp('28671209.gif')"><B>FIGURE 12.9.</B></A><B> </B><I>Examplesof the </I>DrawText<I> function.</I></P><P><BR>First, a TRect record is initialized using the Windows API Rect function. After that,a regular rectangle is drawn on the canvas. (The rectangle is drawn on the canvasso that you can visualize the size of the rectangle that you are about to draw on.)Finally, the DrawText function is called to draw the text.</P><P>Let's take a minute to discuss the various parameters of this function, as follows:</P><UL> <LI>The first parameter is used to specify the device context on which to draw. The Handle parameter of TCanvas is the HDC (handle to a device context) of the canvas, so you pass that for the first parameter. <P> <LI>The second parameter is the string that will be displayed. <P> <LI>The third parameter is used to specify the number of characters to draw. When this parameter is set to -1, all of the characters in the string will be drawn. <P> <LI>The fourth parameter of DrawText takes a var TRect. This parameter is a var parameter because some DrawText operations modify the rectangle passed in. <P> <LI>The key to how DrawText behaves is in the final parameter. This parameter is used to specify the flags that are used when drawing the text. In this example, you use the DT_SINGLELINE, DT_VCENTER, and DT_CENTER flags. These flags tell Windows that the text is a single line, and to draw the text centered both vertically and horizontally. All in all, there are almost 20 flags that you can specify for DrawText. I'm not going to go over every flag, so for a complete list see the Win32 API online help.</UL><P>The previous example illustrates one of the DrawText function's most common uses:to center text either horizontally, vertically, or both. This is a great featurewhen doing owner-drawing of components. In particular, owner-drawn list boxes, comboboxes, and menus often need to center text. You might not realize the benefit ofthis function right now, but you will if you start doing owner-drawn components,or if you start writing your own graphical components.</P><P>Another interesting flag of DrawText is the DT_END_ELLPSIS flag. If the text istoo long to fit in the specified rectangle, Windows truncates the string and addsan ellipsis to the end, indicating the string was truncated. Take this code, forexample:</P><P><PRE>var R : TRect;begin R := Rect(20, 100, 120, 150); DrawText(Canvas.Handle, `This text is too long to fit.', -1, R, DT_END_ELLIPSIS);end;</PRE><P>When this code is executed, it will result in this text being displayed:</P><P><PRE>This text is too long...</PRE><P>You can use this flag any time you anticipate text that could be too long forthe rectangle in which the text is drawn.</P><P>DT_CALCRECT is another flag that is invaluable. It calculates the height of therectangle needed to hold the specified text. When you use this flag, Windows calculatesthe needed height and returns that height but doesn't draw the text. You tell Windowshow wide the rectangle should be, and Windows will tell you how high the rectangleneeds to be to contain the text. In fact, Windows also modifies the bottom and leftmembers of the rectangle passed in so that it contains the needed values. This isparticularly important when drawing multiple lines of text.</P><P>The following example asks Windows how high the rectangle needs to be to containall of the text. After that, a rectangle is drawn onscreen. Finally, the text isdrawn in the rectangle. Here's the code:</P><P><PRE>var R : TRect; S : string;begin R := Rect(20, 150, 150, 200); S := `This is a very long string which will ` + `run into multiple lines of text.'; DrawText(Canvas.Handle, PChar(S), -1, R, DT_CALCRECT or DT_WORDBREAK); Canvas.Brush.Style := bsSolid; Canvas.Rectangle(R.left, R.top, R.right, R.bottom); Canvas.Brush.Style := bsClear; DrawText(Canvas.Handle, PChar(S), -1, R, DT_WORDBREAK);end;</PRE><P>Notice that you have to cast S to a PChar for the second parameter of DrawText.This is necessary because DrawText wants a pointer to a character array for the textparameter and not a string type.</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -