MFC Controls: The List Control |
|
Overview of the List Control |
Overview |
A list control consists of using one of four views to display a list of items. The list is typically equipped with icons that indicate what view is displaying. There are four views used to display items:
|
Practical Learning: Introducing the List Control |
A list control is implemented in the MFC library by the CListCtrl class. At design time, to create a list control, on the Controls toolbox, click the List Control button and click the desired area on a dialog box or a form. Normally, you should expand its dimensions beyond the default assigned because a list control is usually used to display its items on a wide rectangle. To programmatically create a list control, declare a variable or a pointer to CListCtrl. To initialize the control, call its Create() method. Here is an example: BOOL CPictureDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here CListCtrl *lstCtrl = new CListCtrl; lstCtrl->Create(WS_CHILD | WS_VISIBLE, CRect(10, 10, 320, 280), this, 0x285); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } As mentioned already, a list control can display its items in one of four views. To specify the desired view at design time, on the Properties window, select a value from the View combo box. The default value is Icon. The possible values are: |
Icon: To get this value when programmatically creating the control, add the LVS_ICON style: |
Small Icon: This is the same as adding the LVS_SMALLICON style to a dynamic list control |
List: You can get the same result when creating the control with code by adding the LVS_LIST style: |
Report: This view displays the items in explicit columns. It is the same as adding the LVS_REPORT style |
Besides the regular styles, the Win32 library provides extended styles for a list control. To apply an extended style, call the CListCtrl::SetExtendedStyle() method. Its syntax is: DWORD SetExtendedStyle(DWORD dwNewStyle); When calling this method, pass the desired extended style or a combination of these styles as argument. Some of the values are: LVS_EX_CHECKBOXES: The items of the control will display a check box on their left side: LVS_EX_FULLROWSELECT: This style allows the whole row of a Report view to be selected instead of just the item: LVS_EX_GRIDLINES: The control’s items in Report view will display with horizontal grid lines that separate items and vertical grid lines that separate columns items or categories: LVS_EX_TRACKSELECT: When this style is set, if the user positions the mouse on an item for a few seconds without clicking, the item would be automatically selected. The items of a list control can display only within the control, if there are too many of them or the total width of the items is larger than the control can display, it would be equipped with either a vertical scroll bar, a horizontal scroll bar, or both. If you want to prevent scroll bars from displaying even if the list’s items go beyond the allocated rectangle, set the No Scroll property to True or create the control with the LVS_NOSCROLL style. Once the list has been created, the user can select an item by clicking it. To select more than one item, the user can press and hold either Ctrl for random selection or Shift for range selection. Here is an example of a random selection: If you do not want the user to be able to select more than one item at a time, set the Single Selection property to True or create the control with the LVS_SINGLESEL style. Any item that is selected is highlighted. When the user clicks another control or another application, you can decide whether you want the item(s) selected to still show its (their) selection. State. This characteristic is controlled at design time by the Show Selection Always property. By default, it is set to False, meaning that when the control looses focus or its parent application is deactivated, an item that is selected would not show it. Otherwise, you can set this property to True to indicate the selected item even when the control is not active. This property is available through the LVS_SHOWSELALWAYS style. When creating the list, its items are sorted in alphabetical order using the items text as reference. Even if you add items later on, they are inserted in the appropriate order. This sorting feature is controlled at design time by the Sort combo box box. By default, the items of a list control are sorted in alphabetical order using the Ascending value or the LVS_SORTASCENDING style. If you want items to be sorted in reverse alphabetical order, set this property to Descending or create the control with the LVS_SORTDESCENDING style. |
Practical Learning: Creating a List Control |
|
Items of a List Control |
After visually adding or dynamically creating a list control, the next action you probably would take is to populate the control with the desired items. This can be taken care of by calling the CListCtrl::InsertItem() method. One of its syntaxes is as follows: int InsertItem(const LVITEM* pItem ); This version requires an LVITEM pointer as argument. The LVITEM structure is defined as follows: typedef struct _LVITEM { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPTSTR pszText; int cchTextMax; int iImage; LPARAM lParam; #if (_WIN32_IE >= 0x0300) int iIndent; #endif } LVITEM, FAR *LPLVITEM; The mask member variable is used to specify the types of values you want to set for the current item. The value of iItem specifies the index of the item that is being changed. The first item would have an index of 0. The second would be 1, etc. The iSubItem member variable is the index of the sub item for the current value. If the current item will be the leader, the iSubItem is stored in a 0-based array. If it is a sub item, then it is stored in a 1-based array.
The pszText member variable is the string that will display as the item. You can specify the length of this text by assigning a value to the
cchTextMask variable. BOOL COthersDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here LVITEM lvItem; lvItem.mask = LVIF_TEXT; lvItem.iItem = 0; lvItem.iSubItem = 0; lvItem.pszText = "Sandra C. Anschwitz"; m_List.InsertItem(&lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = 1; lvItem.iSubItem = 0; lvItem.pszText = "Roger A. Miller"; m_List.InsertItem(&lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = 2; lvItem.iSubItem = 0; lvItem.pszText = "Marie-Julie W. Gross"; m_List.InsertItem(&lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = 3; lvItem.iSubItem = 0; lvItem.pszText = "Ella Pius Roger"; m_List.InsertItem(&lvItem); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } The state member variable of the LVITEM structure specifies what to do with the new item. For example, once the item has been added, you may want to prepare it for deletion prior to a cut-and-paste operation, in which case you would give it a value of LVIS_CUT. If the item is involved in a drag-and-drop operation, you can assign it a state value of LVIS_DROPHILIGHTED. To give focus to the item, set its state value to LVIS_FOCUSED. An item with an LVIS_SELECTED state value will be selected. Besides the above version of the CListCtrl::InsertItem() method, the CListCtrl class provides this other version: int InsertItem(int nItem, LPCTSTR lpszItem); This is a good simplification of the earlier version. The nItem argument is the index of the new item to de added. Like the LVITEM::iItem member variable, the value of this argument is 0 if the item will be the leader. The lpszItem value is the string that will be used to lead the current item. |
Practical Learning: Populating a List Control |
|
The Report View |
Whether you use the first or the second version, the InsertItem() method allows you to create the item that will display for the Icon, the Small Icon, or the List views of the control. If you plan to display the list in Report view (or to allow the user to transition from various views) and you want to provide more information for each item, you must “create” a report of information for each item. Among the possible views available for a list control, one of them can display columns. This view is called the report view. This view is not required for a list view but it is the only one that provides more detailed information about the items of the list. If you plan to display that view on your list control, then you should create columns. (Alternatively, you can omit creating columns and instead provide headers of columns separately, which can be done using the CHeaderCtrl class. Otherwise, the list control provides the means of creating columns for its report view.) To create the column(s) of a list control, you can use the CListCtrl::InsertColumn() method. One of its syntaxes is: int InsertColumn(int nCol, const LVCOLUMN* pColumn); The nCol argument is the index of the column that this call will create. typedef struct _LVCOLUMN { UINT mask; int fmt; int cx; LPTSTR pszText; int cchTextMax; int iSubItem; #if (_WIN32_IE >= 0x0300) int iImage; int iOrder; #endif } LVCOLUMN, FAR *LPLVCOLUMN; The mask member variable is used to specify what attribute of the column you want to define with this
LVCOLUMN variable. BOOL COthersDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here LVCOLUMN lvColumn; int nCol; lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 120; lvColumn.pszText = "Full Name"; nCol = m_List.InsertColumn(0, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 100; lvColumn.pszText = "Profession"; m_List.InsertColumn(1, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 80; lvColumn.pszText = "Fav Sport"; m_List.InsertColumn(2, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 75; lvColumn.pszText = "Hobby"; m_List.InsertColumn(3, &lvColumn); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } The iOrder member variable is used to identify the column addressed by the
LVCOLUMN variable. int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1); This version simplifies the first a little bit. The nCol argument is the index of the column that will be configured. The second argument,
lpszColumnHeading, is the string that will be displayed on the column header. It follows the same rules as the
LVCOLUMN::pszText member variable. BOOL SetItemText(int nItem, int nSubItem, LPTSTR lpszText); The nItem argument is the index of the column whose information you are adding. It can be the return value of a previously called
InsertColumn(). The pieces of information for each item are stored in a 0-based array. The index of the current sub item is specified using the nSubItem argument. The
lpszText is the actual text that will display under the column for the current item. |
BOOL COthersDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here LVCOLUMN lvColumn; lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 120; lvColumn.pszText = "Full Name"; m_List.InsertColumn(0, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 75; lvColumn.pszText = "Profession"; m_List.InsertColumn(1, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 80; lvColumn.pszText = "Fav Sport"; m_List.InsertColumn(2, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 75; lvColumn.pszText = "Hobby"; m_List.InsertColumn(3, &lvColumn); LVITEM lvItem; int nItem; lvItem.mask = LVIF_TEXT; lvItem.iItem = 0; lvItem.iSubItem = 0; lvItem.pszText = "Sandra C. Anschwitz"; nItem = m_List.InsertItem(&lvItem); m_List.SetItemText(nItem, 1, "Singer"); m_List.SetItemText(nItem, 2, "HandBall"); m_List.SetItemText(nItem, 3, "Beach"); lvItem.mask = LVIF_TEXT; lvItem.iItem = 1; lvItem.iSubItem = 0; lvItem.pszText = "Roger A. Miller"; nItem = m_List.InsertItem(&lvItem); m_List.SetItemText(nItem, 1, "Footballer"); m_List.SetItemText(nItem, 2, "Tennis"); m_List.SetItemText(nItem, 3, "Teaching"); lvItem.mask = LVIF_TEXT; lvItem.iItem = 2; lvItem.iSubItem = 0; lvItem.pszText = "Marie-Julie W. Gross"; nItem = m_List.InsertItem(&lvItem); m_List.SetItemText(nItem, 1, "Student"); m_List.SetItemText(nItem, 2, "Boxing"); m_List.SetItemText(nItem, 3, "Programming"); lvItem.mask = LVIF_TEXT; lvItem.iItem = 3; lvItem.iSubItem = 0; lvItem.pszText = "Ella Pius Roger"; nItem = m_List.InsertItem(&lvItem); m_List.SetItemText(nItem, 1, "Architect"); m_List.SetItemText(nItem, 2, "Ping-Pong"); m_List.SetItemText(nItem, 3, "Songo"); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE }
Practical Learning: Implementing a Detail View of a List Control |
|
Views Transition |
You can create a list control that displays its items in a single view or you can allow the user to change from one view to another. As mentioned already, at design time or when programmatically creating the list control, you can set the initial view using either the View combo box to select a view’s value or by adding one of the view styles. If you want to display only that initial view, you can stop there. Otherwise, you can provide a means of changing views. Because the view displayed on a list control is part of its style, in order to programmatically change its view mode, you can first retrieve the control’s style using the GetWindowLong() function. The GetWindowLong() function only retrieves the current style of the control. You may need to check it first before changing it. This can be done by ANDing the value of the GetWindowLong() function with the LVS_TYPEMASK constant. After checking the view of the control, you can then change its style by calling the SetWindowLong() function. Here is an example: void COthersDlg::OnIconBtn() { // TODO: Add your control notification handler code here LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE); mListStyle &= ~LVS_TYPEMASK; mListStyle |= LVS_ICON; SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle); } void COthersDlg::OnSmallIconBtn() { // TODO: Add your control notification handler code here LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE); mListStyle &= ~LVS_TYPEMASK; mListStyle |= LVS_SMALLICON; SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle); } void COthersDlg::OnListBtn() { // TODO: Add your control notification handler code here LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE); mListStyle &= ~LVS_TYPEMASK; mListStyle |= LVS_LIST; SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle); } void COthersDlg::OnReportBtn() { // TODO: Add your control notification handler code here LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE); mListStyle &= ~LVS_TYPEMASK; mListStyle |= LVS_REPORT; SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle); }
|
Practical Learning: Changing the View of a List Control |
|
List Control and Icons |
A list control can be configured to display pictures that accompany either the columns, the list items, or both. If you want to display a bitmap on the column, you should declare and initialize a CImageList variable. Then call the CListCtrl::SetImageList() method and pass it as argument. If you plan to do this, and if you are using the first version of the CListCtrl::InsertColumn() method that takes an LVCOLUMN pointer as argument, then add the LVCF_IMAGE value to the mask variable and add the LVCFMT_IMAGE value to the fmt variable. To specify the image that will display on the column header, assign its index to the value of the iImage variable. Here is an example: BOOL COthersDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here LVCOLUMN lvColumn; CImageList *ImgHeaders = new CImageList; ImgHeaders->Create(16, 16, ILC_MASK, 1, 1); ImgHeaders->Add(AfxGetApp()->LoadIcon(IDI_UP)); ImgHeaders->Add(AfxGetApp()->LoadIcon(IDI_LOSANGE)); m_List.SetImageList(ImgHeaders, LVSIL_SMALL); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_IMAGE; lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE; lvColumn.cx = 120; lvColumn.pszText = "Full Name"; lvColumn.iImage = 0; m_List.InsertColumn(0, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 100; lvColumn.pszText = "Profession"; m_List.InsertColumn(1, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_IMAGE; lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE; lvColumn.iImage = 1; lvColumn.cx = 80; lvColumn.pszText = "Fav Sport"; m_List.InsertColumn(2, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 75; lvColumn.pszText = "Hobby"; m_List.InsertColumn(3, &lvColumn); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } To use bitmaps or icons on a list control’s items, you should first create bitmaps or icons. If you do not plan to use the Report view and you want to use bitmaps, you can create a long bitmap that will be made of small pictures of the same size. Each picture will be used for each item. Normally, each picture should have a size of 16x16 or less. An example would be: This bitmap is made of 6 pictures of the same dimensions. If you do not plan to use the Report view and you plan to use icons, create each icon with a 16x16 size. CImageList* SetImageList(CImageList* pImageList, int nImageList); The pImageList argument is a CImageList variable or pointer previously initialized. The nImageList is a flag that specifies the type of image list used. It can have one of the following values:
To associate a picture with a list item, you can use one of the following versions of the CListCtrl::InsertItem() methods: int InsertItem(int nItem, LPCTSTR lpszItem, int nImage ); int InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam ); The nImage argument is the index of the image used for the item. The nState argument is the same as the LVITEM::state member variable introduced earlier and used to specify what to do with the item, whether to select it, give it focus, getting it ready for a cut-and-paste operation, or highlighted for a drag-and-drop operation. The nStateMask argument is used in conjunction with the nState argument. It is used to specify what exact type of information, defined by the state flag, that will be changed or retrieved on the item. |
Practical Learning: Associating Bitmap With a List Control’s Items |
|
|
||
Home | Copyright © 2005-2016, FunctionX | |
|