Topic : Common Controls
Author : Unknown
Page : << Previous 7  Next >>
Go to page :

a pointer to a DRAWITEMSTRUCT type object. This structure contains all the information we need to draw an item of list box or combo box: the DC handle, the item's state, the item data, the position and size where the drawing should be applied. The following portion of the overridden function shows how to load correct bitmap by examining nIDCtl and lpDrawItemStruct->itemData:

(Code omitted)

Five local variables are declared: bmp is used to load the bitmap; dcMemory is used to create memory DC and implement image copying; ptrBmpOld is used to restore the original state of dcMemory; ptrDC is used to store the target DC pointer, which is obtained from hDC member of structure DRAWITEMSTRUCT; bm is used to store the information (including dimension) of the bitmap; rect is used to store the position and size where the bitmap should be copied.

From the above source code we can see, if the control is IDC_LIST, we load one of the four bitmaps (IDB_BITMAP_SMILE_1, IDB_BITMAP_SMILE_2, IDB_BITMAP_SMILE_3 or IDB_BITMAP_SMILE_4) according to the value of lpDrawItemStruct->itemData. If the control is IDC_COMBO, we load IDB_BITMAP_BUTTON_SEL or IDB_BITMAP_BIG_SMILE_1 if the item is selected; and load IDB_BITMAP_BUTTON_UNSEL or IDB_BITMAP_BIG_SMILE_2 if the item is not selected. Here, ODS_SELECTED bit of member lpDrawItemStruct->itemState is checked to retrieve item's state.

The following portion of function CCCtlDlg::OnDrawItem(...) draws the bitmap:

(Code omitted)

Only after the bitmap is loaded successfully will we draw the list box or combo box item. First function CDC::FromHandle(...) is called to obtain a CDC type pointer from HDC handler. Then we create a memory DC (compatible with target DC) and select bmp into this DC. Next, function CDC::BitBlt(...) is called to copy the bitmap from memory DC to target DC. For list box items, there is no special bitmaps for their selected states. In case if an item is selected, the corresponding normal bitmap will be drawn using DSTINVERT mode. This will cause every pixel of the bitmap to change to its complement color. When we pass DSTINVERT to function CDC::BitBlt(...), its fifth argument can be set to NULL.

12 Tree Control

Tree control allows us to organize objects into a tree structure. One good example of this type of applications would be a file manager. A tree control can be implemented in both a view window and a dialog box. To implement tree control in a view, we can implement the view using class CTreeView. To implement tree control in a dialog box, we need to use CTreeCtrl class. In this section we will focus on dialog box implementation of tree control.

Like other common controls, we can add tree control resources to the dialog template when designing application's resource. The tree control will have an ID, which could be used to access the control (by either calling function CWnd::GetDlgItem(...) or adding CTreeCtrl type member variable).

Image List

We can associate a bitmap image with each node contained in the tree control. This will make the tree control more intuitive. For example, in a file manager application, we may want to use different images to represent different file types: folder, executable file, DLL file, etc. Before using the images to implement the tree control, we must first prepare them. For tree control (also list control and tab control), these images must be managed by Image List, which is supported by class CImageList in MFC.

Class CImageList can keep and manage a collection of images with the same size. Each image in the list is assigned a zero-based index. After an image list is created successfully, it can be selected into the tree control. We can associate a node with any image contained in the image list. Here image drawing is handled automatically.

If we provide mask bitmaps, only the unmasked portion of the images will be drawn for representing nodes. A mask bitmap must contain only black and white colors. Besides preparing mask bitmaps by ourselves, we can also generate mask bitmaps from the normal images.

To use class CImageList, first we need to declare a CImageList type variable. If we create an image list dynamically by using "new" operator, we need to release the memory when it is no longer in use. Before adding images to the list, we need to call function CImageList::Create(...) to initialize it. This function has several versions, the following is one of them:

BOOL CImageList::Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow);

Here cx and cy indicate the dimension of all images, nInitial represents the number of initial bitmaps that will be included in the image list, nGrow specifies the number of bitmaps that can be added later. Parameter nFlags indicates bitmap types, it could be ILC_COLOR, ILC_COLOR4, ILC_COLOR8, etc., which specify the bitmap format of the images. For example, ILC_COLOR indicates default bitmap format, ILC_COLOR4 indicates 4-bit DIB format (16-color), ILC_COLOR8 indicates 8-bit DIB format (256-color). We can combine ILC_MASK with any of these bitmap format flags to let the image be drawn with transparency.

The images can be added by calling function CImageList::Add(...). Again, this function has three versions:

int CImageList::Add(CBitmap *pbmImage, CBitmap *pbmMask);

int CImageList::Add(CBitmap *pbmImage, COLORREF crMask);

int CImageList::Add(HICON hIcon);

The image list can be created from either bitmaps or icons. For the first version of this function, the second parameter is a pointer to the mask bitmap that will be used to implement transparent background drawing. The second version allows us to specify a background color that can be used to generate a mask bitmap from the normal image. Here parameter crMask will be used to create the mask bitmap: all pixels in the source bitmap that have the same color with crMask will be masked when the bitmap is being drawn, and their colors will be set to the current background color. We can choose a background color by calling function CImageList::SetBkColor(...).

To use image list with a tree control, we need to call function CTreeCtr::SetImageList(...) to assign it to tree control. Then, when creating a node for the tree control, we can use the bitmap index to associate any node with this image.

Adding Nodes

At the beginning, the tree control does not contain any node. Like other common controls, we can initialize it in function CDialog::OnInitDialog(). To add a node to the tree, we need to call function CTreeCtrl::InsertItem(...).

This function also has several versions. The following is the one that has the simplest format:

int CTreeCtrl::InsertItem(LPTV_INSERTSTRUCT lpInsertStruct);

The only parameter to this function is a TV_INSERTSTRUCT type pointer:

typedef struct _TV_INSERTSTRUCT{


HTREEITEM hInsertAfter;

TV_ITEM item;


In a tree control, nodes are managed through handles. After a node is created, it will be assigned an HTREEITEM type handle. Each node has a different handle, so we can use the handle to access a specific node. In the above structure, member hParent indicates which node is the parent of the new node. If we assign NULL to this member, the new node will become the root node. Likewise, member hInsertAfter is used to indicate where the new node should be inserted. We can specify a node handle, or we can use predefined parameters TVI_FIRST, TVI_LAST or TVI_SORT to insert the new node after the first node, last node or let the nodes be sorted automatically.

Member item is a TV_ITEM type object, and the structure contains the information of the new node:

typedef struct _TV_ITEM {

UINT mask;


UINT state;

UINT stateMask;

LPSTR pszText;

int cchTextMax;

int iImage;

int iSelectedImage;

int cChildren;

LPARAM lParam;


In order to add new nodes, we need to understand how to use the following four members of this structure: mask, pszText, iImage and iSelectedImage.

Member mask indicates which of the other members in the structure contain valid data. Besides mask, every member of this structure has a corresponding mask flag listed as follows:

(Table omitted)

In order to use members pszText, iImage and iSelectedImage, we need to set the following bits of member mask:


Member pszText is a pointer to a null-terminated string text that will be used to label this node. Member iImage and iSelectedImage are indices to two images contained in the image list that will be used to represent the node's normal and selected state respectively.

By calling function CTreeCtrl::InsertItem(...) repeatedly, we could create a tree structure with desired number of nodes.


Sample 12\CCtl demonstrates how to use tree control in a dialog box. It is a dialog based application generated by Application Wizard. There is only one tree control IDC_TREE in the dialog template. To access it, a member variable CCCtlDlg::m_treeCtrl is added for IDC_TREE through using Class Wizard.

To create the image list, five bitmap resources are prepared, whose IDs are IDB_BITMAP_CLOSEDFOLDER, IDB_BITMAP_DOC, IDB_BITMAP_LEAF, IDB_BITMAP_OPENFOLDER and IDB_BITMAP_ROOT respectively. These bitmaps have the same dimension.

In function CCCtlDlg::OnInitDlalog(), the image list is created as follows:

(Code omitted)

A CBitmap type local variable bmp is declared to load the bitmap resources. First, function CImageList::Create(...) is called to create the image list. Here macro BMP_SIZE_X and BMP_SIZE_Y are defined at the beginning of the implementation file, they represent the dimension of the bitmaps:

#define BMP_SIZE_X 16

#define BMP_SIZE_Y 15

We use ILC_MASK flag to let the bitmaps be drawn with transparent background. Originally the image list has five bitmaps,

Page : << Previous 7  Next >>