Teach Yourself Visual C++® 5 in 24 Hours

Previous chapterNext chapterContents


- Hour 17 -
Using Image Lists and Bitmaps

Image lists can be used to store collections of bitmaps, making them useful when several bitmaps are needed, such as in tree view and list view controls. In this hour, you learn

Also, in this hour you will build a sample program that creates an image list and uses it as a storage location for bitmap images. This hour will build a foundation that you will use later in Hour 18, "List View Controls," and Hour 19, "Tree Views."

What Is an Image List?

An image list is similar to an array of bitmaps, just like a roll of film is an array of images, as shown in Figure 17.1. Unlike rolls of film, an image list can grow, if needed, as extra images are added to the list. Each bitmap stored in an image list is associated with an index, which can be used to retrieve a particular image.

Figure 17.1.
An image list is like a roll of bitmap images.


Time Saver: Image lists can also be used outside these new controls, and they provide an easy way to store a series of bitmaps, because you must handle only a single image-list object instead of separate objects for each bitmap.

If you want to display bitmaps in tree views or list views, you must use an image list. If your program needs to manage several different bitmapped images, a single image list is easier to use than a series of bitmaps. Accessing and displaying multiple images from an image list is much easier than handling multiple CBitmap objects. Windows Explorer has a much richer user interface than the older File Manager used in Windows 3.1. Much of this richness is achieved through the use of image lists, which offer an easy way to store and manage bitmaps.

In addition, image lists offer two features that are difficult to duplicate with regular bitmaps:

New Term: A transparent image is an image that allows the background to be seen through part of the image, as if part of the bitmap were transparent.

A transparent image is difficult to achieve using a normal bitmap. In the simplest cases, about twice as many lines of code are required to draw a bitmap transparently as are required to draw it as an opaque image against a drawing surface. Using an image list, drawing a transparent bitmap is almost effortless, requiring little more than parameters that are set correctly.

New Term: An overlaid image is created by combining two images to form a single, combined image.

An overlaid image is useful when showing special attributes for items represented by images stored in an image list. For example, when a shared directory is shown in the Explorer, a server "hand" is superimposed over the directory's folder. This is an overlaid image.

How Is an Image List Used?

As for almost everything else in Windows, there is an MFC class for image lists, too. The CImageList class is used to create, display, and otherwise manage image lists in an MFC-based Windows program.

Image lists often are used to provide item images for the CListCtrl class that is covered in Hour 18, and the CTreeCtrl class that is covered in Hour 19. However, you can also use an image list as a collection of bitmaps, which you will do in this chapter. Using image lists in this way helps show off the different things you can do with image lists before they are used with the common controls.

As an example of using image lists, create an SDI project named ImageList. This project uses an image list to display a series of bitmaps in the program's client area.

Creating an Image List

The first step in creating an image list is to create a series of bitmaps, each of which is the same size. Although the images can be any size, the sample code in this section assumes the bitmaps are 32 pixels on each side. The bitmaps used in the example are shown in Figure 17.2.

Figure 17.2.
The bitmaps used in the ImageList example are all the same size.

Create the three bitmaps, and name them as shown in Table 17.1.

Table 17.1. Bitmaps used in the ImageList project.

ID Description
IDB_CROSS Cross mark
IDB_CHECK Check mark
IDB_BANG Exclamation point

Storing a bitmap image in an image list consists of three steps:

1. Load the bitmap.

2. Create a new image index in the image list that contains a copy of the bitmap.

3. Delete the bitmap object.

The bitmap object is deleted because the image list makes a copy of the bitmap and stores the image internally. As a rule of thumb, any time a Windows GDI object is loaded, it should be deleted to prevent memory leaks. The preceding steps are handled by AddBitmapToImageList, a new function added to the CImageListView class. Add the function provided in Listing 17.1 to the ImageListView.cpp source file.

TYPE: Listing 17.1. The CImageListView::AddBitmapToImageList function.

BOOL CImageListView::AddBitmapToImageList( UINT nResourceID )

{

    BOOL bReturn;

    CBitmap bmp;



    bReturn = bmp.LoadBitmap( nResourceID );

    if( bReturn != FALSE )

    {

        int nReturn = m_imageList.Add( &bmp, RGB(255,255,255) );

        bmp.DeleteObject();

    }

    return bReturn;

} The AddBitmapToImageList function is used because three bitmap resources are added to the image list. Adding the bitmaps using a new member function reduces the amount of code you must write and helps reduce the chance of errors, because every bitmap is loaded using the same function.

The CImageList::Add member function is used to add an image to the image list. The version of Add used in Listing 17.1 takes two parameters:


Time Saver: The background color is used when drawing transparent images using masked bitmaps. If you aren't using a masked image list, the COLORREF value is ignored.

After adding the member function to the ImageListView.cpp file, add the source code from Listing 17.2 to the CImageListView class, found in the file ImageListView.h. Add the source code in the class implementation section, which is marked by the // Implementation comment. After the comment, there is a protected: label inserted by AppWizard for user- supplied variables and functions.

TYPE: Listing 17.2. Source code to be added to the CImageListView class.

protected:

    BOOL        AddBitmapToImageList( UINT nResourceID );

CImageList m_imageList; The actual work of creating the image list is done when the view is constructed. The image list can be built at any time; however, it is costly to create an image list in terms of computing power. Creating the image list in the constructor lets you build it once, rather than each time it is used. Add the source code from Listing 17.3 to the constructor for CImageViewList.

TYPE: Listing 17.3. The CImageListView constructor.

CImageListView::CImageListView()

{

    m_imageList.Create( 32, 32, TRUE, 3, 1 );



    AddBitmapToImageList( IDB_CROSS );

    AddBitmapToImageList( IDB_CHECK );

    AddBitmapToImageList( IDB_BANG );

} The image list is created using one of the CImageList::Create functions. This version of Create is useful when an image list is used as a bitmap collection; I use other versions of Create in the following chapters. This version of Create has five parameters:

New Term: A masked image list is an image list that contains two bitmaps for each image--the second bitmap is a mask that is used when drawing transparent images. Parts of the image that are visible are colored black in the mask, parts that are transparent are colored white in the mask.

Displaying an Image List Using the CImageList::Draw Function

Individual items stored in an image list can be drawn using the CImageList::Draw member function, as shown in Listing 17.4.

TYPE: Listing 17.4. Using CImageList::Draw to display a bitmap from an image list.

void CImageListView::OnDraw(CDC* pDC)

{

    CPoint ptImage( 0, 0 );

    for( int nImage = 0; nImage < 3; nImage++ )

    {

        m_imageList.Draw( pDC, nImage, ptImage, ILD_NORMAL );

        ptImage.x += 50;

    }

} The Draw member function has four parameters:

Compile and run the ImageList project. Figure 17.3 shows the current version of the ImageList application running.

Figure 17.3.
Using ILD_NORMAL to display the contents of the image list.

There are eight different types of drawing operations:

Figure 17.4 shows the image list items drawn using the ILD_MASK style. This allows you to see the image mask generated by the image list.

Figure 17.4.
Image list items mask drawn using ILD_MASK.

The individual image bitmaps stored in an image list can also be extracted as icons using the ExtractIcon member function:

HICON hicon = m_imageList.ExtractIcon( nImage );

The only parameter needed for ExtractIcon is the image index. You can then use the icon extracted just like any icon handle. Icons were discussed in Hour 14, "Icons and Cursors."

Displaying a Transparent Image

There are two methods you can use to display an image transparently:

Using a Background Color

A simple method for drawing a transparent image is to define the background color that is used on the image background. The background color of the image list will then be adjusted to match the surface background color, allowing the drawing surface to "shine through," giving the image a transparent effect. Replace the CImageList::OnDraw function with the code provided in Listing 17.5, and then recompile and run the ImageList program.

TYPE: Listing 17.5. Using the CImageList::Draw function to display a bitmap transparently.

void CImageListView::OnDraw(CDC* pDC)

{

    m_imageList.SetBkColor( RGB(0,255,0) );

    CPoint ptImage( 0, 0 );

    for( int nImage = 0; nImage < 3; nImage++ )

    {

        m_imageList.Draw( pDC, nImage, ptImage, ILD_NORMAL);

        ptImage.x += 50;

    }

} If you compile and run the ImageList project, the background of the images will be set to green. By changing the RGB COLORREF value passed to the CImageList::SetBkColor function, you can match any background color.

Using the ILD_TRANSPARENT Flag

Another transparent drawing method is to use the ILD_TRANSPARENT flag when CImageList::Draw is called. This tells the image list to combine the image mask with the bitmap, if a mask exists. If the image list is not masked, the image is drawn as if ILD_NORMAL was used.

Displaying an Overlapped Image

An overlapped image is two images from the same bitmap, with one image superimposed on the other. Before using an image as an overlay, it must be defined as an overlay image. You can define up to four bitmaps per image list as overlays using the CImageList::SetOverlayImage function:

m_imageList.SetOverlayImage( 0, 1 );

The SetOverlayImage function takes two parameters: the image index used as the overlay, and the overlay index used to identify the overlay.


Just a Minute: Just to make things more interesting, unlike almost every other index used in Windows, the overlay index starts at one instead of zero.

To use an overlaid image, the CImageList::Draw function is used as in previous examples, except that the ILD_OVERLAYMASK flag is used. The INDEXTOOVERLAYMASK macro is combined with the ILD_OVERLAYMASK flag to specify the overlay image index to be combined with the base image. Listing 17.6 is a new version of OnDraw that displays an overlaid image using an image list.

TYPE: Listing 17.6. Using the CImageList::Draw function to display an overlapped image.

void CImageListView::OnDraw(CDC* pDC)

{

    m_imageList.SetBkColor( CLR_NONE );

    CPoint ptOverlay( 50, 80 );

    m_imageList.SetOverlayImage( 0, 1 );

    m_imageList.Draw( pDC,

                      2,

                      ptOverlay,

 INDEXTOOVERLAYMASK(1) );

}

Summary

In this chapter, you learned about image lists, a convenient way to display images in a Windows program. You used image lists to draw a series of bitmaps that were opaque, transparent, or overlaid with a second image.

Q&A

Q I have a bitmap that has a white background color, and also uses white in the bitmap. How can I draw the background transparently and still draw the white parts of the bitmap?

A Use the bitmap image mask instead of the color mask. One version of the CImageList::Add member function allows you to add two bitmaps to the image list:
nReturn = m_imageList.Add( &bmpImage, &bmpMask );
The second bitmap is a mask bitmap. The parts of the image bitmap that correspond to black pixels on the mask bitmap will be drawn. The parts of the image bitmap that correspond to white pixels will be transparent in the final image.

Q How can I store an icon image in an image list?

A A version of the CImageList::Add member function accepts an icon handle:
nReturn = m_imageList.Add( hIcon );

Workshop

The Workshop is designed to help you anticipate possible questions, review what you've learned, and begin thinking ahead to putting your knowledge into practice. The answers to the quiz are in Appendix B, "Quiz Answers."

Quiz

1. What are the two basic types of image lists?

2. Why would you want to have a "grow-by" parameter greater than one when creating an image list?

3. What is a transparent image?

4. The color mask is passed as a parameter when adding a bitmap image to the image list. What is the color mask used for?

5. What drawing style is used to draw the mask for a transparent image?

6. What are the drawing styles that begin with ILD_BLEND used for?

7. After a bitmap has been added to the image list, are you required to destroy the bitmap object or will the image list destroy it for you?

8. What is an overlapped image?

Exercises

1. Use an overlay image to combine two images.

2. Experiment by using the Draw function with the ILD_BLENDxx values to see how the system highlight color is combined with different types of images.


Previous chapterNext chapterContents


Macmillan Computer Publishing USA

© Copyright, Macmillan Computer Publishing. All rights reserved.