![]() |
Desktop Development »
Combo & List Boxes »
Beginners
Beginner
Using the CListBox controlBy Wolfram SteinkeAn entry level tutorial on using the CListBox control. |
VC6Win2K, MFC, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
This tutorial will show how to use the CListBox class in a very basic dialog based application. It will cover the following points:
CListBox to your dialog
CListBox
CListBox Styles
CListBox and deleting items
CListBox messages
This tutorial assumes the you are comfortable with creating a dialog based application using the VC++ 6 Class Wizard. If you require information on this topic, consult the article A Beginners Guide to Dialog Based Applications - Part 1.
When your dialog-based application is generated, go to the Resources in the Workspace window. Select the dialog IDD_LISTBOXTUTORIAL_DIALOG in the Dialog section. To insert the list box control, select it from the Control palette. The cross shaped cursor indicates where the centre of the list box will be placed.

Drag the edges of the control out to the desired size.
There are 4 different styles of list box with different selection properties. To change the style of the list box, right click on it and select Properties. Then select the Styles tab.

LBN_SELCHANGE notification is sent to the parent dialog. When a double click is used, a LBN_DBLCLK notification is sent as well.
If you want a Read Only list box, use None along with the Notify style turned off, so no notification messages will sent.
SetColumnWidth member function sets the width of the columns. Vertical scroll is ignored and if you want a scroll bar, set the Horizontal Scroll style.
It is not possible to change these styles at runtime even though ModifyStyle() may give the impression it does. If you want, turn the Sort style on and off. For example, it is best to construct the list box by calling new and Create, then deleting it and creating a new one when the style is to be changed. Alternatively, you can have 2 list boxes superimposed and hide the one with the incorrect style.
In the Demo, the list box headed 'Toggle List Style' changes the LBN_SORT style. The code deletes the old list box and creates a new one each time the Toggle button is clicked.
void CListBoxTutorialDlg::OnToggleListStyle() { TRACE("CListBoxTutorialDlg::OnToggleListStyle( )\n"); if( m_pFlyList ) delete m_pFlyList; CRect rc; CString str = _T(""); m_Template.GetWindowRect( &rc ); ScreenToClient( &rc ); m_pFlyList = new CListBox; m_ListStyle ^= LBS_SORT; m_pFlyList->Create( m_ListStyle, rc, this, IDC_LIST1 ); m_pFlyList->ModifyStyleEx( 0, WS_EX_CLIENTEDGE ); // set font same as dialog to be sure they are the same m_pFlyList->SetFont( GetFont() ); for( int j=0; j<10; j++ ) { str.Format( "Item %d", j+1 ); int idx = m_pFlyList->AddString( str ); m_pFlyList->SetItemData( idx, j+1 ); } // reset the checkbox m_InsertRemove = 0; UpdateData(FALSE); }
Adding a string to the list box is quite straight forward by simply calling the AddString() function. If the list box has the LBN_SORT style, the new item is inserted to its correct place. Otherwise, it is added to the end of the list.
CString str;
for( int i=0; i<NumOfLists; i++ )
for( int j=0; j<10; j++ )
{
str.Format( "Item %d", j+1 );
m_List[i].AddString( str );
}
Unless you are appending new items to an existing list, it is a good idea to call ResetContent() first, in order to be sure that the list is empty to start with.
m_List[5].ResetContent(); // empty the list
Inserting a string is just as straight forward. The difference is however that the item is merely inserted at the specified index and is NOT sorted even if the style is set to LBN_SORT.
void CListBoxTutorialDlg::OnInsertRemove() { TRACE("CListBoxTutorialDlg::OnInsertRemove( )\n"); UpdateData(); if( m_InsertRemove ) { int idx = m_pFlyList->InsertString( 4, "Item 11" ); m_pFlyList->SetItemData( idx, 11 ); } else { int idx = m_pFlyList->FindString( -1, "Item 11" ); m_pFlyList->DeleteString( idx ); } }
In the code snippet above, there is also an example of the use of DeleteString() which simply removes the item at the specified index. Use FindString() or FindStringExact() to find the index of the string to be deleted if it is not known.
If you use Data Exchange, the string variable will be filled with the selected string when you call UpdateData(TRUE).
Add an OnSelChanged function for the list box with Class Wizard.

In the demo project, you will see the use of the macro ON_CONTROL_RANGE(LBN_SELCHANGED,.. which is not inserted by Class Wizard but is a way of handling all list boxes in the one handler, provided their IDs are sequential.
Single selection list boxes simply load the string variable with the selected string when UpdateData(TRUE) is called, as shown in the middle part of the function.
m_strReport.Format( "The selection in List %d has changed to %s", list+1, m_strSelection[list]);
In a list box where Data Exchange is not available, as shown in the Style Toggle List, call GetCurSel() and then GetText().
{
CString str;
int idx = m_pFlyList->GetCurSel();
m_pFlyList->GetText( idx, str );
DWORD dw = m_pFlyList->GetItemData( idx );
m_strReport.Format( "The selection in List 7 "
"has changed to %s\n Index = %d,
and ItemData = %d", str, idx, dw);
}
For multiple and extended selection list boxes, you must first determine how many items are selected. The indexes are then loaded into an array and then use these to retrieve the strings.
.
.
int list = nID - IDC_LIST2;
if( list == 1 || list == 2 )
{
// Multi selections
int count = m_List[list].GetSelCount();
CArray< int,int > arrayListSel;
arrayListSel.SetSize(count); // make room in array
m_List[list].GetSelItems(count,
arrayListSel.GetData()); // copy data to array
CString str = _T("");
for( int i=0; i< count; i++ )
{
CString tmp = _T("");
m_List[list].GetText( arrayListSel[i], tmp );
str += (tmp + _T(", "));
}
m_strReport.Format( "The selection in List %d has changed to %s",
list+1, str);
}
else
.
.
A list box returns the string of the selected item as shown above. Often the program actually uses a value other than the string or the index, and what's more, you need to get this value correct whether the items in the list are sorted or not. If the application is to support multiple languages, this is even more important because sorting can be different.
To assist with this, each item in the list can have a DWORD associated with it, and this remains attached to the string regardless of the sorting.
Use SetItemData( idx, dwData ) and GetItemData( idx ). When setting the data, use the index returned by the AddString() or InsertString() functions to ensure you get it right.
for( int j=0; j<10; j++ ) { str.Format( "Item %d", j+1 ); int idx = m_pFlyList->AddString( str ); m_pFlyList->SetItemData( idx, j+1 ); }
To retrieve the data, get the item index and call GetItemData(idx).
.
.
{
CString str;
int idx = m_pFlyList->GetCurSel();
m_pFlyList->GetText( idx, str );
DWORD dw = m_pFlyList->GetItemData( idx );
m_strReport.Format( "The selection in List 7 "
"has changed to %s\n Index = %d,
and ItemData = %d", str, idx, dw);
}
.
.
Selecting an item can be done by setting the index as below:
You can use SetCurSel( idx ) for single selection.
OR use SelectString( after, str ) where after is the index after which to start searching. As you can see from the demo, the items are added in a different order to which they are displayed and the data remains matched.
m_List[0].SetCurSel( 2 ); m_pFlyList->SelectString( -1, "Item 4" );
In multi selection and extended selection, call SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem ). If bSelect is TRUE, the items are selected and highlighted and if FALSE, the items are deselected. If the nFirstItem, nLastItem are the same, only a single item is done.
m_List[1].SelItemRange( TRUE, 3, 8 ); m_List[1].SelItemRange( FALSE, 5, 5 );
The notification messages available for list boxes are the following. The list box must have LB_NOTIFY style.
LBN_ERRSPACE notification message when a list box cannot allocate enough memory to meet a specific request.
LBN_SELCHANGE notification message when the selection in a list box is about to change.
LBN_DBLCLK notification message when the user double-clicks a string in a list box.
LBN_SETFOCUS notification message when a list box receives the keyboard focus.
LBN_KILLFOCUS notification message when a list box loses the keyboard focus.
LBN_SELCANCEL notification message when the user cancels the selection in a list box. The demo handles the LBN_SELCHANGE and LBN_DBLCLK messages.
You may like to experiment with the VKeyToItem and CharToItem.
VKeyToItem - Override to provide custom WM_KEYDOWN handling for list boxes with the LBS_WANTKEYBOARDINPUT style set.
CharToItem - Override to provide custom WM_CHAR handling for owner-draw list boxes which don't have strings. The message handlers in this tutorial are the most commonly used and should indicate that they need not be very complex. More complex issues are handled elsewhere on this site.
Happy programming!
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 23 Mar 2001 Editor: Smitha Vijayan |
Copyright 2000 by Wolfram Steinke Everything else Copyright © CodeProject, 1999-2010 Web18 | Advertise on the Code Project |