分享

MFC Controls: The List Control

 DavinTang 2010-11-16

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:

  • Icons: The control displays a list of items using icons with a 32x32 pixels size of icons. This is the preferred view when the main idea consists of giving an overview of the items
  • Small Icons: Like the other next two views, it uses 16x16 pixel icons to display a simplified list of the items. Once more, no detail is provided about the items of this list. The list is organized in disparate columns with some on top of others. If the list is supposed to be sorted, the alphabetical arrangement is organized from left to right.
  • List: This list, using small icons, is also organized in columns; this time, the columns are arranged so that the first column gets filled before starting the second. If the list is sorted, the sorting is arranged in a top-down manner.
  • Report: This view displays arranged columns of items and provides as many details as the list developer had arranged it.

 

Practical learning Practical Learning: Introducing the List Control

  1. Start Microsoft Visual C++ or Visual Studio and create an MFC Application named DeptStore2
  2. Create it as Dialog Based
  3. Delete the TODO line and the OK button
  4. Change the Caption of the Cancel button to Close
 

List Control Creation

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 List control 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 Practical Learning: Creating a List Control

  1. On the Toolbox, click the List Control and click the dialog box
    Change its ID to IDC_STORE_ITEMS
     
  2. Right-click the list control and click Add Variable…
  3. Set the Variable Name to m_StoreItems
     
  4. Click Finish
 

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.

After initializing the LVITEM variable, you can pass it to the InsertItem() method to add it as a new item to the list. Here is an example that creates items and displays as a List view:

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 Practical Learning: Populating a List Control

  1. To create a new dialog box, on the main menu, click Project -> Add Resource…
  2. In the Add Resource dialog box, click Dialog and click New
  3. Change the ID of the dialog box to IDD_STOREITEMS_DLG
  4. Design the dialog box as follows:
     
    Control ID Caption
    Static Text   Item #:
    Edit Control IDC_ITEMNUMBER  
  5. Right-click the dialog box and click Add Class…
  6. Set the Class Name to CNewStoreItemDlg and base it on CDialog
     
  7. Click Finish
  8. Add a CString Value Variable associated with the Item # edit control and name it m_ItemNumber
  9. Display the first dialog box. Under the list control, add a Button and set its properties as follows:
    Caption: New Item
    ID: IDC_NEWITEM
  10. Double-click the new button to generate its OnBnClicked event
  11. In the top section of the file, type:
     
    // DeptStore2Dlg.cpp : implementation file
                                //
                                #include "stdafx.h"
                                #include "DeptStore2.h"
                                #include "DeptStore2Dlg.h"
                                #include ".\deptstore2dlg.h"
                                #include "NewStoreItemDlg.h"
                                #ifdef _DEBUG
                                #define new DEBUG_NEW
                                #endif
  12. Implement the event as follows:
     
    void CDeptStore2Dlg::OnBnClickedNewitem()
                                {
                                // TODO: Add your control notification handler code here
                                CNewStoreItemDlg dlg;
                                srand( (unsigned)time(NULL) );
                                char strNumber[20];
                                int number1 = rand() % 999;
                                int number2 = rand() % 999;
                                sprintf(strNumber, "%d-%d", number1, number2);
                                dlg.m_ItemNumber = strNumber;
                                if( dlg.DoModal() )
                                {
                                LVITEM lvItem;
                                lvItem.mask = LVIF_TEXT;
                                lvItem.iItem = 0;
                                lvItem.iSubItem = 0;
                                lvItem.pszText = strNumber;
                                this->m_StoreItems.InsertItem(&lvItem);
                                }
                                }
  13. Execute the application and create a few item numbers
 

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.

The pColumn argument is an LVCOLUMN pointer. This structure is defined as follows:

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.

The fmt member variable formats the text of the column. For example, it can be used to align the text of the column to the left (the default) (LVCFMT_LEFT), the center (LVCFMT_CENTER), or the right (LVCFMT_RIGHT). If you do not set a value for this member variable, the text will be aligned to the left. If you plan to set a value for this variable, then add the LVCF_FMT value for the mask member variable.

The cx variable is used to specify the width occupied by the text of the column. If you do not set a value for this property, the column would initially appear so narrow its text would not display. Therefore, unless you have a good reason to omit it, you should always specify the value of this variable. If you plan to set a value for this property, then add the LVCF_WIDTH value to the mask member variable.

The pszText is the string that will appear as the text of the column. Just like all the other member variables, this one is not required but, besides the rectangle that limits the column header, this member is probably the most important characteristic of a column because it informs the user as to what this column is used for. The string of this variable can be provided as a null-terminated value. Like all other strings used in an MFC application, this string can also be a value of a String Table item. It can also be retrieved from an array of strings. To set a value for this member variable, add the LVCF_TEXT value to the mask variable. The length of this string can be specified by assigning a value to the cchTextMax member variable.

After initializing the LVCOLUMN variable, pass it as the CListCtrl::InsertColumn() second argument. Here is an example:

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.

Besides, or instead of, the above version of the CListCtrl::InsertColumn() method, you can use the following version to create columns for the control:

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.

The optional nFormat argument is used to specify the horizontal alignment of the lpszColumnHeading text. It can be set to LVCFMT_LEFT for left alignment (the default), LVCFMT_CENTER for center alignment, or LVCFMT_RIGHT for right alignment. If you do not specify this argument, the text would be aligned to the left. The nWidth argument is used to set the width of the column header in pixels. If you do not want to specify this argument, pass it at –1. The nSubItem is used to set the index of the sub item used on the current column.

With the columns configured, you must provide a string that will be displayed under a particular column header for an item. To do this, you must first specify which item will use the information you are going to add. The InsertColumn() method returns an integer that is the index of the new item. You can use this returned value to identify the column whose information you are adding. Then to specify a string for each column of the current item, call the CListCtrl::SetItemText() method. Its syntax is:

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.

Here is an example:

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 Practical Learning: Implementing a Detail View of a List Control

  1. Display the first dialog box and click the list control on it
  2. In the Properties window, change its View property to Report
     
  3. To create the columns of the list control, access the OnInitDialog() event of the main dialog box and change it as follows:
     
    BOOL CDeptStore2Dlg::OnInitDialog()
                                {
                                CDialog::OnInitDialog();
                                // Set the icon for this dialog. The framework does this automatically
                                // when the application's main window is not a dialog
                                SetIcon(m_hIcon, TRUE); // Set big icon
                                SetIcon(m_hIcon, FALSE); // Set small icon
                                // TODO: Add extra initialization here
                                LVCOLUMN lvColumn;
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_CENTER;
                                lvColumn.cx = 60;
                                lvColumn.pszText = "Item #";
                                this->m_StoreItems.InsertColumn(0, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_LEFT;
                                lvColumn.cx = 100;
                                lvColumn.pszText = "Category";
                                this->m_StoreItems.InsertColumn(1, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_LEFT;
                                lvColumn.cx = 160;
                                lvColumn.pszText = "Item Name";
                                this->m_StoreItems.InsertColumn(2, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_LEFT;
                                lvColumn.cx = 80;
                                lvColumn.pszText = "Size";
                                this->m_StoreItems.InsertColumn(3, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_RIGHT;
                                lvColumn.cx = 60;
                                lvColumn.pszText = "Unit Price";
                                this->m_StoreItems.InsertColumn(4, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_RIGHT;
                                lvColumn.cx = 30;
                                lvColumn.pszText = "Qty";
                                this->m_StoreItems.InsertColumn(5, &lvColumn);
                                this->m_StoreItems.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
                                return TRUE; // return TRUE unless you set the focus to a control
                                }
  4. To prepare creating a complete item, access the second dialog box and change its design as follows:
     
    Control Caption ID Other Properties
    Static Text Category:    
    Combo Box   IDC_CATEGORIES Data: Babies;Teens;Women;Men;Miscellaneous
    Static Text Item Name:    
    Edit Control   IDC_ITEMNAME  
    Static Text Item Size:    
    Edit Control   IDC_ITEMSIZE  
    Static Text Qty:    
    Edit Control   IDC_QUANTITY  
    Static Text Unit Price:    
    Edit Control   IDC_UNITPRICE  
    Static Text Item #:    
    Edit Control   IDC_ITEMNUMBER  
    Button OK IDOK  
    Button Cancel IDCANCEL  
  5. Create the CString Value Variables associated with the controls as follows:
     
    ID Value Variable
    IDC_CATEGORIES m_Categories
    IDC_ITEMNAME m_ItemName
    IDC_ITEMSIZE m_ItemSize
    IDC_QUANTITY m_Quantity
    IDC_UNITPRICE m_UnitPrice
  6. Access the main dialog box. Double-click its New Item button and change its implementation as follows:
     
    void CDeptStore2Dlg::OnBnClickedNewitem()
                                {
                                // TODO: Add your control notification handler code here
                                CNewStoreItemDlg dlg;
                                srand( (unsigned)time(NULL) );
                                char strNumber[20];
                                int number1 = rand() % 999;
                                int number2 = rand() % 999;
                                sprintf(strNumber, "%d-%d", number1, number2);
                                dlg.m_ItemNumber = strNumber;
                                if( dlg.DoModal() )
                                {
                                LVITEM lvItem;
                                int nItem;
                                lvItem.mask = LVIF_TEXT;
                                lvItem.iItem = 0;
                                lvItem.iSubItem = 0;
                                lvItem.pszText = strNumber;
                                nItem = this->m_StoreItems.InsertItem(&lvItem);
                                this->m_StoreItems.SetItemText(nItem, 1, dlg.m_Category);
                                this->m_StoreItems.SetItemText(nItem, 2, dlg.m_ItemName);
                                this->m_StoreItems.SetItemText(nItem, 3, dlg.m_ItemSize);
                                this->m_StoreItems.SetItemText(nItem, 4, dlg.m_UnitPrice);
                                this->m_StoreItems.SetItemText(nItem, 5, dlg.m_Quantity);
                                }
                                }
  7. Execute the application and create a few items as follows (let the computer generate the item numbers):
     
     
    Category Item Name Size Qty Unit Price
    Women Cashmere Lined Glove 8 12 115.95
    Miscellaneous Chocolate Gift Box Medium 5 45.00
    Men Trendy Jacket Medium 8 45.85
    Women Stretch Flare Jeans Petite 6 27.75
    Women Belted Sweater Large 10 15.95
    Teens Girls Classy Handbag One Size 4 95.95
    Women Casual Dress Shoes 9.5M 16 45.95
    Babies Infant Girls Ballerina Dress 2M 14 22.85
    Teens Girls Velour Dress 10 8 12.55
    Women Lace Desire Panty M 22 7.15
    Teens Boys Hooded Sweatshirt M (7/8) 16 42.75
    Men Classic Pinstripe Suit 38 8 145.90
  8. Close the dialog box and return to your programming environment
 

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 Practical Learning: Changing the View of a List Control

  1. In the Class View, expand DeptStore2. Right-click CDeptStore2Dlg -> Add -> Add Function…
  2. Set the Return Type to DWORD and the Function Name to GetViewType
  3. Click Finish and implement the method as follows:
     
    DWORD CDeptStore2Dlg::GetViewType(void)
                                {
                                return (GetStyle() & LVS_TYPEMASK);
                                }
  4. In the Class View, right-click CDeptStore2Dlg -> Add -> Add Function…
  5. Set the Return Type to void and the Function Name to SetViewType
  6. Set the Parameter Type to DWORD
  7. In the Parameter Name, type dwViewType and click Add
  8. Click Finish and implement the method as follows:r file of the first dialog box and declare two methods as follows:
     
    void CDeptStore2Dlg::SetViewType(DWORD dwViewType)
                                {
                                DWORD dwCurType;
                                HWND hWnd;
                                hWnd = this->m_StoreItems;
                                GetSafeHwnd();
                                dwCurType = ::GetWindowLong(hWnd, GWL_STYLE);
                                dwCurType &= ~LVS_TYPEMASK;
                                dwViewType |= dwCurType;
                                ::SetWindowLong(hWnd, GWL_STYLE, dwViewType);
                                }
  9. Access the first dialog box and add four buttons to it as follows:
     
    Button ID Caption
    IDC_LARGE Large
    IDC_SMALL Small
    IDC_LIST List
    IDC_DETAILS Details
  10. Double-click the Large button and implement its OnBnClicked event as follows:
     
    void CDeptStore2Dlg::OnBnClickedLarge()
                                {
                                // TODO: Add your control notification handler code here
                                SetViewType(LVS_ICON);
                                }
  11. Return to the dialog box. Double-click the Small button and implement its event as follows:
     
    void CDeptStore2Dlg::OnBnClickedSmall()
                                {
                                // TODO: Add your control notification handler code here
                                if( GetViewType() != LVS_SMALLICON)
                                SetViewType(LVS_SMALLICON);
                                }
  12. Return to the dialog box. Double-click its List button and implement the event as follows:
     
    void CDeptStore2Dlg::OnBnClickedList()
                                {
                                // TODO: Add your control notification handler code here
                                if( GetViewType() != LVS_LIST)
                                SetViewType(LVS_LIST);
                                }
  13. Return to the dialog box and double-click the Details button to implement its event as follows:
     
    void CDeptStore2Dlg::OnBnClickedDetails()
                                {
                                // TODO: Add your control notification handler code here
                                if( GetViewType() != LVS_REPORT)
                                SetViewType(LVS_REPORT);
                                }
  14. Save all
 

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.

If you plan to display the control’s items in Report view and you want to use bitmaps, you can create a long bitmap that will made of small pictures of the same size and each picture will be used for each item. Each picture should have a size of 32x32.

If you plan to display the control’s items in Report view and other views, if you want to use bitmaps, you should create two long bitmaps. One would be made of pictures that are 16x16 size. Such pictures would be used for the Small Icon, the List, and the Report views. You should also create the second bitmap made of pictures of 32x32 size. These pictures would be used for the List view.

After creating the bitmap and/or icons, you should declare a variable or a pointer to CImageList class and initialize it using the CImageList::Create() method. To make the image list available to the list control, call the CListCtrl::SetImageList() method. Its syntax is:

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:

Value Description
LVSIL_NORMAL The image list is made of large bitmap or icons, typically 32x32
LVSIL_SMALL The image list is made of small bitmap or icons, typically 16x16
LVSIL_STATE The image list is made of pictures that will be used as mask

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 nMask argument is the same as the LVITEM::mask member variable introduced earlier. It is simply used to specify what information you need to specify on 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.

The lParam argument, as well as the lParam member variable of the TVITEM structure are used to perform a specific operation on the item, such as involving it in a sort algorithm or finding an item.

 

Practical learning Practical Learning: Associating Bitmap With a List Control’s Items

  1. To create bitmap, on the main menu, click Project -> Add Resource... In the Add Resource dialog box, click Bitmap and click New
  2. In the Properties window, change the ID to IDB_LARGEIMG
  3. Set the Height to 32 and the Width to 160
  4. Design the bitmap as follows:
     
  5. To create another bitmap, on the main menu, click Project -> Add Resource... In the Add Resource dialog box, click Bitmap and click New
  6. In the Properties window, change the ID to IDB_SMALLIMG
  7. Set the Height to 16 and the Width to 80
  8. Design the bitmap as follows:
     
  9. Access the header file of the main dialog box and declare two CImageList variables as follows:
     
    private:
                                CImageList m_SmallImg;
                                CImageList m_LargeImg; 
                                };
  10. Access the OnInitDialog() method of the same class and initialize the variables as follows:
     
    BOOL CDeptStore2Dlg::OnInitDialog()
                                {
                                CDialog::OnInitDialog();
                                // Set the icon for this dialog. The framework does this automatically
                                // when the application's main window is not a dialog
                                SetIcon(m_hIcon, TRUE); // Set big icon
                                SetIcon(m_hIcon, FALSE); // Set small icon
                                // TODO: Add extra initialization here
                                LVCOLUMN lvColumn;
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_CENTER;
                                lvColumn.cx = 60;
                                lvColumn.pszText = "Item #";
                                this->m_StoreItems.InsertColumn(0, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_LEFT;
                                lvColumn.cx = 100;
                                lvColumn.pszText = "Category";
                                this->m_StoreItems.InsertColumn(1, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_LEFT;
                                lvColumn.cx = 160;
                                lvColumn.pszText = "Item Name";
                                this->m_StoreItems.InsertColumn(2, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_LEFT;
                                lvColumn.cx = 80;
                                lvColumn.pszText = "Size";
                                this->m_StoreItems.InsertColumn(3, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_RIGHT;
                                lvColumn.cx = 60;
                                lvColumn.pszText = "Unit Price";
                                this->m_StoreItems.InsertColumn(4, &lvColumn);
                                lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
                                lvColumn.fmt = LVCFMT_RIGHT;
                                lvColumn.cx = 30;
                                lvColumn.pszText = "Qty";
                                this->m_StoreItems.InsertColumn(5, &lvColumn);
                                this->m_StoreItems.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
                                m_SmallImg.Create(IDB_SMALLIMG, 16, 1, #ffffff); 
                                m_LargeImg.Create(IDB_LARGEIMG, 32, 1, #fffff5); 
                                m_List.SetImageList(&m_SmallImg, LVSIL_SMALL); 
                                m_List.SetImageList(&m_LargeImg, LVSIL_NORMAL);
                                return TRUE; // return TRUE unless you set the focus to a control
                                }
  11. To use the images, change the OnBnClicked event of the New Item button as follows:
     
    void CDeptStore2Dlg::OnBnClickedNewitem()
                                {
                                // TODO: Add your control notification handler code here
                                CNewStoreItemDlg dlg;
                                srand( (unsigned)time(NULL) );
                                char strNumber[20];
                                int number1 = rand() % 999;
                                int number2 = rand() % 999;
                                sprintf(strNumber, "%d-%d", number1, number2);
                                dlg.m_ItemNumber = strNumber;
                                if( dlg.DoModal() )
                                {
                                LVITEM lvItem;
                                int nItem;
                                int imgNbr;
                                if( dlg.m_Category == "Babies" )
                                imgNbr = 0;
                                else if( dlg.m_Category == "Teens" )
                                imgNbr = 1;
                                else if( dlg.m_Category == "Women" )
                                imgNbr = 2;
                                else if( dlg.m_Category == "Men" )
                                imgNbr = 3;
                                else // if( dlg.m_Category == "Miscellaneous" )
                                imgNbr = 4;
                                lvItem.mask = LVIF_IMAGE | LVIF_TEXT;
                                lvItem.iItem = 0;
                                lvItem.iSubItem = 0;
                                lvItem.pszText = strNumber;
                                lvItem.iImage = imgNbr;
                                nItem = this->m_StoreItems.InsertItem(&lvItem);
                                this->m_StoreItems.SetItemText(nItem, 1, dlg.m_Category);
                                this->m_StoreItems.SetItemText(nItem, 2, dlg.m_ItemName);
                                this->m_StoreItems.SetItemText(nItem, 3, dlg.m_ItemSize);
                                this->m_StoreItems.SetItemText(nItem, 4, dlg.m_UnitPrice);
                                this->m_StoreItems.SetItemText(nItem, 5, dlg.m_Quantity);
                                }
                                }
  12. Execute the application
     

Kontera
What's this? Close
Webnary
Translate to 21 languages for free
Translate
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多