📄 ch12.htm
字号:
<BLOCKQUOTE> <P><HR><strong>NOTE:</strong> If you are writing components that can be used with all versions of Delphi, you cannot use the cast from string to PChar. This cast won't compile under Delphi 1. Instead, you have to use the StrPCopy function as follows:</P> <PRE>var Temp : array [0..50] of Char; R : TRect; S : string;begin DrawText(Canvas.Handle, StrPCopy(Temp, S), -1, R, DT_CALCRECT or DT_WORDBREAK);{ etc. } </PRE></BLOCKQUOTE><PRE></PRE><BLOCKQUOTE> <P>If you don't have to worry about supporting Delphi 1, you can cast the string to a PChar as shown previously. <HR></BLOCKQUOTE><P>Place this code in the OnPaint event handler for a form. Run the program severaltimes and modify the length of the text string that is displayed. Notice that nomatter how much text you add to the string, the rectangle will always be drawn preciselyaround the text. Refer to Figure 12.9 for the results of this exercise as well asthe results of the previous exercises on DrawText.</P><BLOCKQUOTE> <P><HR><strong>TIP:</strong> If you need even more text drawing options, you can use the DrawTextEx function. See the Win32 API online help for full details. <HR></BLOCKQUOTE><P><strong>NOTE:</strong> Drawing text with DrawText is slightly slower than using TextOut.If your drawing operations are speed-sensitive, you should use TextOut rather thanDrawText. You'll have to do more work on your own, but the execution speed will likelybe better. For most drawing, though, you won't notice any difference between TextOutand DrawText.</P><P>DrawText is a very useful and powerful function. When you start writing your owncomponents, you will no doubt use this function a great deal.</P><P><H3><A NAME="Heading8"></A>Drawing Bitmaps</H3><P>Drawing bitmaps sounds like it should be difficult, yet as you have seen severaltimes up to this point, drawing bitmaps is very easy. The TCanvas class has severalmethods for drawing bitmaps. The most often-used method is the Draw method. Thismethod simply draws a bitmap (represented by a descendant of the TGraphic class)onto the canvas at the specified location. You've seen several examples up to thispoint, but here's another short example:</P><P><PRE>var Bitmap : TBitmap;begin Bitmap := TBitmap.Create; Bitmap.LoadFromFile(`c:\winnt\winnt256.bmp'); Canvas.Draw(0, 0, Bitmap); Bitmap.Free;end;</PRE><P>This code creates a TBitmap object, loads the file called WINNT256.BMP, and displaysit in the upper-left corner of the form. Use Draw when you want to display bitmapswithout modification.</P><P>The StretchDraw method is used when you want to alter a bitmap's size. You specifya rectangle for the location of the bitmap and an image to draw. If the suppliedrectangle is larger than the original size of the bitmap, the bitmap will be stretched.If the rectangle is smaller than the bitmap's original size, the bitmap will be reducedto fit. Here's an example:</P><P><PRE>var</PRE><PRE> Bitmap : TBitmap;</PRE><PRE> R : TRect;begin Bitmap := TBitmap.Create; Bitmap.LoadFromFile(`c:.bmp'); R := Rect(0, 0, 100, 100); Canvas.StretchDraw(R, Bitmap); Bitmap.Free;end;</PRE><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> No attempt is made by StretchDraw to maintain the bitmap's original aspect ratio. It's up to you to be sure that the bitmap retains its original width-to-height ratio. <HR></BLOCKQUOTE><P>Another bitmap drawing method is CopyRect. This method enables you to specifyboth a source rectangle and a destination rectangle. This enables you to split abitmap into sections when displaying it. Take this code, for example:</P><P><PRE>var Bitmap : TBitmap; Src : TRect; Dst : TRect; I, X, Y : Integer; Strips : Integer; Stripsize : Integer; OldPal : HPalette;begin Bitmap := TBitmap.Create; Bitmap.LoadFromFile(`factory.bmp'); Strips := 6; Stripsize := (Bitmap.Height div Strips); OldPal := SelectPalette(Canvas.Handle, Bitmap.Palette, True); for I := 0 to Pred(Strips) do begin Src := Rect(0, i * Stripsize, Bitmap.Width, (i * Stripsize) + Stripsize); X := Random(Width - Bitmap.Width); Y := Random(Height - Stripsize); Dst := Rect(X, Y, X + Bitmap.Width, Y + Stripsize); Canvas.CopyRect(Dst, Bitmap.Canvas, Src); end; SelectPalette(Canvas.Handle, oldPal, True); Bitmap.Free;end;</PRE><P>This code loads a bitmap, dissects it into strips, and then displays the stripsin random locations on the form. Figure 12.10 shows a sample run of this code. Enterthis code in the OnPaint handler of your main form and run the program. Cover upthe main form and then bring it to the top again. The images will be redrawn eachtime the form is repainted.</P><P><A HREF="javascript:popUp('28671210.gif')"><B>FIGURE 12.10.</B></A><B> </B><I>Sectionsof a bitmap written randomly to the screen with CopyRect.</I></P><P>Copying sections of a bitmap like FACTORY.BMP might not appear to make a lot ofsense at first glance. A common graphics programming technique, however, is to createone large bitmap made up of several smaller images and copy just the image you wantto the screen. In that type of situation, CopyRect is the way to go.</P><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> In the previous code example I used the SelectPalette function to set the form's palette to the Palette property of the bitmap. For some strange reason, the TCanvas class doesn't have a Palette property, so you have to go to the API to set the palette for the form. If I didn't set the palette for the form, the colors would be wrong when the bitmap strips are displayed on the form. The CopyRect method uses a different mechanism for displaying a bitmap on the canvas, so taking this extra step is necessary when using this method. <HR></BLOCKQUOTE><P>There is one other bitmap drawing method I want to mention. The BrushCopy methodenables you to specify a source rectangle, a destination rectangle, an image, anda transparent color. The online help for BrushCopy says to use the ImageList componentrather than using this method. That's a bit extreme, in my opinion. There are timeswhen BrushCopy works nicely, and it's a whole lot easier to use than the ImageListcomponent. Don't overlook BrushCopy if you are using bitmaps with transparent backgrounds.</P><P><H2>Offscreen Bitmaps</H2><P>Offscreen bitmaps, also called memory bitmaps, are used commonly in Windows programming.Offscreen bitmaps enable you to draw an image in memory and then display the imageonscreen by using the Draw method. Offscreen bitmaps help avoid the flicker thatyou see when you try to draw too much directly to the screen in a short period oftime. Offscreen bitmaps are also good for complex drawing programs. You can preparethe image in memory and then display it when ready. Offscreen bitmaps are used inanimation, and the most popular new technology for animation is Microsoft's DirectXSDK.</P><P>The principle behind offscreen bitmaps is a simple three step process:</P><DL> <DT></DT> <DD><B>1. </B>Create a memory bitmap. <P> <DT></DT> <DD><B>2. </B>Draw on the memory bitmap. <P> <DT></DT> <DD><B>3. </B>Copy the memory bitmap to the screen. <P></DL><H3><A NAME="Heading9"></A>Creating a Memory Bitmap</H3><P>Creating a memory bitmap is easy. In fact, you've already done it several timesin this chapter. Surprised? Each time you created a TBitmap object you were creatinga memory bitmap. In those cases, you were loading a file into the memory bitmap.In other cases you will create a memory bitmap, set the its size, and then draw onit--for example,</P><P><PRE>var Bitmap : TBitmap; I, X, Y, W, H : Integer;</PRE><PRE> Red, Green, Blue : Integer;</PRE><PRE>begin Bitmap := TBitmap.Create; Bitmap.Width := 500; Bitmap.Height := 500; for I := 0 to 19 do begin X := Random(400); Y := Random(400); W := Random(100) + 50; H := Random(100) + 50; Red := Random(255); Green := Random(255); Blue := Random(255); Bitmap.Canvas.Brush.Color := RGB(Red, Green, Blue); Bitmap.Canvas.Rectangle(X, Y, W, H); end; Canvas.Draw(0, 0, Bitmap); Bitmap.Free;end;</PRE><P>To try out this code, place a button on a form and type the code in the eventhandler for the button's OnClick event. Each time you click the button, a new randomset of rectangles is drawn onscreen. This code simply draws on the memory bitmapand then copies the bitmap to the form's canvas. If you are using a 256-color videoadapter, the colors will be dithered because you are not implementing a palette forthis exercise.</P><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> When you create a memory bitmap, the bitmap will have the same color depth as the current video display settings. In other words, if you have your video display set for 256 colors, the memory bitmap will be a 256-color bitmap. If you have your video display set for 24- or 32-bit video, your memory bitmap will contain 32K, 64K, or 16 million colors. <HR></BLOCKQUOTE><H3><A NAME="Heading10"></A>Saving a Memory Bitmap</H3><P>Saving a memory bitmap to a file is ridiculously easy. Here's all it takes:</P><P><H4>BITMAP.SAVETOFILE(`TEST.BMP');</H4><P>Yes, that's it. In fact, you can easily create your own screen capture program.All you have to do is copy the appropriate part of the desktop to a memory bitmapand then save it to file. It looks something like Listing 12.1.</P><P><H4>LISTING 12.1. SCREEN CAPTURE ROUTINE.</H4><PRE>procedure MainForm.CaptureButtonClick(Sender: TObject);var DtCanvas : TCanvas; Bitmap : TBitmap; NumColors : Integer; LogPal : PLogPalette; Src, Dst : TRect;begin { Create a TCanvas object for the desktop DC. } DtCanvas := TCanvas.Create; DtCanvas.Handle := GetDC(0); { Create a new TBitmap object and set its } { size to the size of the form. } Bitmap := TBitmap.Create; Bitmap.Width := Width; Bitmap.Height := Height; { Create a palette from the form's Canvas } { and assign that palette to the Bitmap's } { Palette property. } NumColors := GetDeviceCaps(Canvas.Handle, SizePalette); GetMem(LogPal, SizeOf(TLogPalette) + (NumColors - 1) * SizeOf(TPaletteEntry)); LogPal.palVersion := $300; LogPal.palNumEntries := NumColors; GetSystemPaletteEntries( Canvas.Handle, 0, NumColors, LogPal.palPalEntry); Bitmap.Palette := CreatePalette(LogPal^); FreeMem(LogPal); { Copy a section of the screen from the } { desktop canvas to the Bitmap. } Src := BoundsRect; Dst := Rect(0, 0, Width, Height); Bitmap.Canvas.CopyRect(Dst, DtCanvas, Src); { Save it to disk. } Bitmap.SaveToFile(`form.bmp'); { Clean up and go home. } Bitmap.Free; DtCanvas.Free;end;</PRE><P><strong>NOTE:</strong> This code goes the extra mile and implements a palette for theform in case the form is displaying graphics. This code was translated from the codethat was originally part of an article I wrote for The Cobb Group's <I>C++BuilderDeveloper's Journal</I>. Although you probably aren't interested in the C++Builderjournal, you might be interested in the <I>Delphi Developer's Journal</I>. You cansign up for a free copy of the <I>Delphi Developer's Journal</I> on The Cobb Group'sWeb site at http://www.cobb.com/ddj.</P><P><H3><A NAME="Heading11"></A>Sample Memory Bitmap Program</H3><P>Listing 12.2 contains a program called MemBmp that illustrates the use of memorybitmaps. This program scrolls a marquee across the screen when you click one of twobuttons. The first button scrolls the text across the screen without using a memorybitmap (writing directly to the form's canvas). The second button uses a memory bitmapfor smoother scrolling. A third button is used to stop the marquee. Figure 12.11
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -