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


m_bIsDragging to TRUE, and call function CTreeCtrl::HitTest(...) to find out if the mouse cursor is over any node:

(Code omitted)

Next, we need to obtain dragging image list for this node. The dragging image list is created by calling function CTreeCtrl::CreateDragImage(...). After this, the address of the image list object is stored in variable m_pilDrag. If the image list is created successfully, we call several member functions of CImageList to display the dragging image and enter dragging mode. If not, we should not start dragging, and need to set the content of pResult to a non-zero value, this will stop dragging:

(Code omitted)

WM_MOUSEMOVE

Then we need to implement WM_MOUSEMOVE message handler. Whenever the mouse cursor moves to a new place, we need to call function CImageList::DragMove(...) to move the dragging image so that the image will always follow the mouse's movement. We need to check if the mouse hits a new node by calling function CTreeCtrl::HitTest(...). If so, we must leave dragging mode by calling function CImageList:: DragLeave(...), highlight the new node by calling function CTreeCtrl::SelectDropTarget(...), and enter dragging mode again by calling function CTreeCtrl::DragEnter(...). The reason for doing this is that when dragging is undergoing, the tree control window is locked and no update could be implemented successfully. The following is the implementation of this message handler:

(Code omitted)

WM_LBUTTONUP

Finally we need to implement WM_LBUTTONUP message handler. In this handler, we must first leave dragging mode and end dragging. This can be implemented by calling functions CImageList:: DragLeave(...) and CImageList::EndDrag() respectively. Then, we need to delete dragging image list object:

(Code omitted)

The following code fragment shows how to judge if the source node can be copied to become the child of the target node:

(Code omitted)

If the source and target are the same node, or target node does not have any child node, or source node is the parent node (including indirect parent) of the target node, the copy should not be implemented. Otherwise, we need to call function MCTreeCtrl::CopyItem(...) to implement node copy:

(Code omitted)

If we want the node to be moved instead of being copied, we can delete the source node after copying it. The source node and all its child nodes will be deleted by calling function CTreeCtrl::DeleteItem(...).

Functions CWnd::SetCapture() and ::ReleaseCapture() are also called in MCTreeCtrl:: OnBegindrag(...) and MCTreeCtrl::OnLButtonUp(...) respectively to set and release the window capture. By doing this, we can still trap mouse messages even if it moves outside the client window when dragging is undergoing.

That's all we need to do for implementing drag-n-drop copying. By compiling and executing the sample application at this point, we will be able to copy nodes through mouse dragging. With minor modifications to the above message handlers, we can easily implement both node copy and move as follows: when CTRL key is held down, the node can be copied through drag-n-drop, when there is no key held down, node will be moved.

15 List Control

A list control is another type of control that can be used to manage a list of objects. Rather than storing items in a tree structure, a list control simply organize them into an array. There is no parent or child node in a list control.

A list control can be viewed in different styles: 1) Normal icon style ¾ each item is represented by a big icon. 2) Small icon style ¾ each item is represented by a small icon. 3) List style ¾ all items are represented by small icons contained in a vertical list. 4) Report style ¾ the details of all items are listed in several vertical lists.

In MFC, list control is supported by class CListCtrl. Implementing list control is similar to implementing tree control: the list control resource can be created in dialog template, then the list control can be initialized in the dialog's initialization stage. Each item in the list control can be associated with one or more images, they will be used to represent the item in different styles. Usually we need to associate two images for an item: one big image for normal style, and a small image for other three styles. In general case, we need to prepare two image lists to create a list control.

LV_COLUMN and LV_ITEM

The procedure of initializing list control is similar to that of tree control. First we need to create two image lists: one for normal icon style; one for small icon style. Then we need to call function CListCtrl::SelectImageList(...) to associate the image lists with the list control. The following is the format of this function:

CImageList *CListCtrl::SetImageList(CImageList *pImageList, int nImageList);

Here pImageList is a pointer to the image list, and nImageList specifies the type of image list: it could be LVSIL_NORMAL or LVSIL_SMALL, representing which style the image list will be used for.

After the image list is set, we need to add columns for the list control (Figure 12). This can be implemented by calling function CListCtrl::InsertColumn(...), which has the following format:

int CListCtrl::InsertColumn(int nCol, const LV_COLUMN* pColumn);

The function has two parameters. The first one indicates which column is to be added (0 based index), and the second one is a pointer to LV_COLUMN type object:

typedef struct _LV_COLUMN {

UINT mask;

int fmt;

int cx;

LPSTR pszText;

int cchTextMax;

int iSubItem;

} LV_COLUMN;


Here, member mask indicates which of the other members contain valid values, this is the same with structure LV_ITEM. Member fmt indicates the text alignment for the column, it can be LVCFMT_LEFT, LVCFMT_RIGHT, or LVCFMT_CENTER. Member cx indicates the width of the column, and iSubItem indicates its index. Member pszText is a pointer to the text string that will be displayed for each column. Finally, cchTextMax specifies the size of buffer pointed by pszText.

After columns are created, we need to add list items. For each list item, we need to insert a sub-item in each column. For example, if there are three columns and 4 list items, we need to add totally 12 sub-items.

To add a sub-item, we need to stuff an LV_ITEM type object then call function CListCtrl:: InsertItem(...), which has the following format:

int CListCtrl::InsertItem(const LV_ITEM* pItem);

The following is the format of structure LV_ITEM:

typedef struct _LV_ITEM {

UINT mask;

int iItem;

int iSubItem;

UINT state;

UINT stateMask;

LPSTR pszText;

int cchTextMax;

int iImage;

LPARAM lParam;

} LV_ITEM;


The usage of this structure is similar to that of structure TV_ITEM. For each item, we need to use this structure to add every sub-item for it. Usually only the sub-items contained in the first column will have an associated image (when being displayed in report style), so we need to set image for each item only once. Member iItem and iSubItem specify item index and column index respectively.

Sample

Sample 15\CCtl demonstrates how to use list control. It is a dialog-based application generated by Application Wizard. In this sample, a four-item list is implemented, which can be displayed in one of the four styles. When it is displayed in report style, the control has four columns. The first column lists four shapes: square, rectangle, circle, triangle. The second column lists the formula for calculating their perimeter, and the third column lists the formula for calculating their area.

Creating Image Lists

In the dialog template, the list control has an ID of IDC_LIST. In order to access this control, a CListCtrl type variable m_listCtrl is added to class CCCtldlg through using Class Wizard.

Four icon resources are added to the application for creating image lists. Their IDs are IDI_ICON_SQUARE, IDI_ICON_RECTANGLE, IDI_ICON_CIRCLE and IDI_ICON_TRIANGLE respectively. In the previous samples, we created image list from bitmap resource all the time. Actually, it can also be created from icon resources as well.

In function CCCtlDlg::OnInitDialog(), first two image lists are created and selected into the list control:

(Code omitted)

We could use the same icon to create both 32(32 and 16(16 image lists. When creating the 16(16 image list, the images will be automatically scaled to the size specified by the image list. Since we allocate memory for creating image list in dialog's initialization stage, we need to release it when the dialog box is being destroyed. For this purpose, a WM_DESTROY message handler is added through using Class Wizard, within which the image lists are deleted as follows:

(Code omitted)

If we release the memory used by image lists this way, we must set "Share image list" style for the list control. This allows image list to be shared among different controls. If we do not set this style, the image list will be destroyed automatically when the list control is destroyed. In this case, we don't have to release the memory by ourselves. To set this style, we need to invoke "List control properties" property sheet, go to "More styles" page, and check "Share image list" check box (Figure 13).

(Figure 13 omitted)

Creating Columns

First we need to create three columns, whose titles are "Shape", "Perimeter", and "Area" respectively. The following portion of function CCCtlDlg::OnInitDialog() creates each column:

(Code omitted)

The client window's dimension is retrieved by calling function CWnd::GetClientRect(...) and then stored in variable rect. The horizontal size of each column is set to 1/3 of the width of the client window.

Creating Sub-items

Since there are totally three columns, for each item, we need to create three

Page : << Previous 10  Next >>