We've covered the background information you need to create and use brushes based on bitmaps. Now let's put that information to work. Let's say that you want to draw a rectangle filled in with a brush that looks like little bricks, as shown in Figure 12-14.
The bitmap you need has a pixel pattern that looks like this:
This is a monochrome bitmap with a height and width of 8. Here are three methods you can use to create a brush based on this bitmap.
Create an 8-by-8 monochrome bitmap in SDKPAINT that resembles the diagram shown above and save it under the name BRICK.BMP. In your resource script file, include a statement identifying this file as a bitmap and naming it ”Brick“:
Brick BITMAP brick.bmp
Within your program, define variables of type HBITMAP (handle to a bitmap) and HBRUSH (handle to a brush):
HBITMAP hBitmap ;
HBRUSH hBrush ;
These two handles are set by the following statements:
hBitmap = LoadBitmap (hInstance, "Brick") ;
hBrush = CreatePatternBrush (hBitmap) ;
When you have a valid device context, select the brush into the device context and display the rectangle:
SelectObject (hdc, hBrush) ;
Rectangle (hdc, xLeft, yTop, xRight, yBottom) ;
When you release the device context, delete the brush and bitmap:
DeleteObject (hBrush) ;
DeleteObject (hBitmap) ;
You don't have to wait until you release the device context to delete the bitmap—you can do so anytime after you create the brush based on the bitmap.
This method defines the bitmap pixels within the program as an array of eight unsigned integers. Each integer corresponds to a scan line in the bitmap pattern. A 1 bit is used for white and a 0 bit for black:
HBITMAP hBitmap ;
HBRUSH hBrush ;
static WORD wBrickBits [] =
{ 0xFF, 0x0C, 0x0C, 0x0C, 0xFF, 0xC0, 0xC0, 0xC0 } ;
The bitmap is created using CreateBitmap by referencing this array of integers:
hBitmap = CreateBitmap (8, 8, 1, 1, (LPSTR) wBrickBits) ;
hBrush = CreatePatternBrush (hBitmap) ;
SelectObject (hdc, hBrush) ;
Rectangle (hdc, xLeft, yTop, xRight, yBottom) ;
After you're finished with the brush and the bitmap (and the brush is no longer selected in a valid device context), you delete the bitmap and the brush:
DeleteObject (hBrush) ;
DeleteObject (hBitmap) ;
Rather than using an array of integers for the bitmap's bits, you can use instead an array of unsigned characters. Because each scan line must contain an even number of bytes, however, you have to insert a 0 after each byte:
static unsigned char cBrickBits [] =
{ 0xFF, 0, 0x0C, 0, 0x0C, 0, 0x0C, 0,
0xFF, 0, 0xC0, 0, 0xC0, 0, 0xC0, 0 } ;
This method is similar to the second method except that you use the logical bitmap and logical brush structures to create the bitmap and the brush. Begin by defining these variables:
HBITMAP hBitmap ;
HBRUSH hBrush ;
static BITMAP bitmap = { 0, 8, 8, 2, 1, 1 } ;
static LOGBRUSH logbrush = { BS_PATTERN, 0L } ;
static WORD wBrickBits [] =
{ 0xFF, 0x0C, 0x0C, 0x0C, 0xFF, 0xC0, 0xC0, 0xC0 } ;
The last field of the logical bitmap structure remains uninitialized. This field must contain a far pointer to the array of bytes that define the bitmap pattern. Do not initialize the structure with this pointer, however. Instead use an assignment statement:
bitmap.bmBits = (LPSTR) wBrickBits ;
Watch out when you assign a far address of a local data item to the field of a structure. If the program's data segment is moved in memory (as it can be following a GetMessage, LocalAlloc, or LocalReAlloc call), that far address can become invalid. A good rule is to make this assignment immediately before using the structure. After the assignment, you use this structure to create the bitmap:
hBitmap = CreateBitmapIndirect (&bitmap) ;
Now that you have the handle to a bitmap, you can use the CreateBrushIndirect function to create the brush:
logbrush.lbHatch = hBitmap ;
hBrush = CreateBrushIndirect (&logbrush) ;
SelectObject (hdc, hBrush) ;
Rectangle (hdc, xLeft, yTop, xRight, yBottom) ;
Later on, delete both the brush and the bitmap:
DeleteObject (hBrush) ;
DeleteObject (hBitmap) ;