A Dual ListBox Selection Manager

I created a class named CDualListManager that handles all of the drudgery of moving items between the two lists. One list represents the list of available items and the other represents the list of choosen items (I use the word choosen instead of selected to avoid any confusion with the hilighted item in a list). This class is intended to be a member of CDialog, CFormView or CPropertyPage. All the parent class has to do is properly initialize this class and call a couple of member functions and this class will take care of the following things:
- If the "Add" button is pressed the selected item(s) are moved from the available list to the choosen list.
- If the "Add All" button is pressed all of the items in are moved from the available list to the choosen list.
- If the "Remove" button is pressed the selected item(s) are moved from the choosen list to the available list.
- If the "Remove All" button is pressed all of the items in are moved from the choosen list to the available list.
- If the "Move Up" button is pressed the selected item(s) in the choosen list are moved up in the list by one. This button can be pressed repeatedly until all of the selected items have reached the top of the list. When that occurs the button is disabled.
- If the "Move Down" button is pressed the selected item(s) in the choosen list are moved down in the list by one.
- Allows double clicking on an item to move it to the opposite list.
- When item(s) are moved from one list to another the item that was moved is selected in the list it was moved to. The list that had the item removed selects the item that is at the location of the first item that was moved. If the item at the bottom of the list is moved the item immediately above it is selected. If the last item in the list is removed there is no selection.
- Enabling/disabling of buttons - when items are moved between lists and up and down in the choosen list the availability of buttons changes. For instance if an item is moved to the top of the choosen list the "Move Up" button doesn't make sense. When this occurs the "Move Up" button is automatically disabled.
- Keyboard support - disabling a button that has the focus causes problems for keyboard users. This code checks to see if a button has the focus before it disables it. If it does the focus is forwarded to the next avaiabled control.
How to use this class:
- Add a member variable of this class type to the dialog box, property page or form view where you want to use it.
- From the initialization method (OnInitDialog() for a dialog box and a property page and OnInitialUpdate() for a view) do the following things in this order:
- Add the items to the available and choosen lists with the calls AddItemToAvailableList(...) and AddItemToChoosenList(...). The first parameter is the name of the item and the second parameter is a unique identifier for the item.
- Call InitializeControls(...) with a pointer the parent window and the IDs of all of the controls.
- Override OnCmdMsg(...)
Notes:
- If you don't need certain features (like the ability to move an item up or down in the choosen list) simply provide a NULL value for that id. The rest of the class will continue work correctly. The IDs for the two lists are required since a dual list manager doesn't make sense unless it has two lists to work with.
- This code will work with single, multiple and extended listboxes.
- The order of the controls doesn't matter. You can put the choosen list on the left, right, top or bottom of the selected list. Just make sure you supply the control IDs in the right order.
The demo application uses this dual list manager in a form view, a dialog box and a property page. This code will show how to use it in a form view.
Make the following changes to OnInitialUpdate
void CDualListDemoView::OnInitialUpdate()
{
... // Normal processing
// ADDED TO DEFAULT THE LISTS.
// This code will need to be replaced with your
// application specific code that knows what belongs
// in each list.
m_DualListManager.AddItemToAvailableList(_T("Red"), 0);
m_DualListManager.AddItemToAvailableList(_T("Green"), 1);
m_DualListManager.AddItemToAvailableList(_T("Blue"), 2);
m_DualListManager.AddItemToChoosenList(_T("Yellow"), 3);
m_DualListManager.AddItemToChoosenList(_T("Purple"), 4);
m_DualListManager.AddItemToChoosenList(_T("Orange"), 5);
// ADDED TO INITIALIZE THE MANAGER CLASS
m_DualListManager.InitializeControls(this,
IDC_FV_LIST_AVAILABLE,
IDC_FV_LIST_CHOOSEN,
IDC_FV_ADD,
IDC_FV_ADD_ALL,
IDC_FV_REMOVE,
IDC_FV_REMOVE_ALL,
IDC_FV_MOVE_UP,
IDC_FV_MOVE_DOWN);
}
Override the OnCmdMsg method and add a call to the ProcessCmdMsg on the Dual List Manager Object.
BOOL CDualListDemoView::OnCmdMsg(UINT nID, int nCode,
void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// ADDED TO INTERCEPT MESSAGE THAT THE DUAL
// LIST MANAGER NEEDS
m_DualListManager.ProcessCmdMsg(nID, nCode);
// NOW CALL THE BASE CLASS
return CFormView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
Add the following member to your header file.
CDualListManager m_DualListManager;
Downloads
Download demo project - 33 KbDownload source - 9 Kb

Comments
Add Clear and Refill members
Posted by t.buys on 10/06/2005 06:15amIn my project I need this kind of class in a wizzard mode property sheet. Because the user can switch between the property pages I need some functionality to remove the items from the listboxes and add new items to them. I add two new members: Clear() and Refill(). I also add a boolean m_bIsAttached which is set TRUE after the Attach calls in the InitializeControls(...) member.
void CDualListManager::Clear() { if(m_bIsAttached) { m_ArrayAvailable.RemoveAll(); m_ArrayChoosen.RemoveAll(); m_KeyMap.RemoveAll(); } } void CDualListManager::Refill() { if(m_bIsAttached) { // Re-fill the listboxes with the contents of the array FillListboxes(); // Select the first item in each of the listboxes SelectLBItem(m_ctrlAvailableList, 0); SelectLBItem(m_ctrlChoosenList, 0); // Now enable/disable the move buttons based on the contents and selction // state of the listbox controls. EnableButtons(); } }ReplyUpdate for XP style manifest and flicker
Posted by t.buys on 09/29/2005 09:51amI like this class but there are some little problems. If using the XP style manifest the buttons sending notify messages even when not clicked on them. Solution: in ProcessCmdMsg add
if (nCode == BN_CLICKED) { .... }around the button handlers. When clicking on the up and down button the Available list is flickering. To stop that add at member FillListboxes an extra parameter BOOL bUpDown with the default value FALSE. Add in functionif (!bUpDown) { .... }around the first code part like:if (!bUpDown) { m_ctrlAvailableList.ResetContent(); iCount = m_ArrayAvailable.GetSize(); for(iIndex = 0; iIndex < iCount; ++iIndex) { m_KeyMap.Lookup(m_ArrayAvailable[iIndex], csName); iIndex2 = m_ctrlAvailableList.AddString(csName); m_ctrlAvailableList.SetItemData(iIndex2, m_ArrayAvailable[iIndex]); } }and change the call in the MoveUpOrDown member like After all I think it will be handy to access the data from listboxes. Add two public member functions:CListBox* CDualListManager::GetChoosenListBox() { return &m_ctrlChoosenList; } CListBox* CDualListManager::GetAvailableListBox() { return &m_ctrlAvailableList; }ReplyGood, but not complete
Posted by Legacy on 01/20/2004 12:00amOriginally posted by: scgeorge
I look for a solution to save proportion in form window, while resizing.If you know how to solve this, please send me an e-mail.
Thanks forward.
ReplyClistControll
Posted by Legacy on 03/03/2003 12:00amOriginally posted by: javaid hussain
Hell,
Replyi am javaid, from Pakistan. i tested your program. that was good for the begineers. and so that they can explore the window concepts.this realy help someone to motivate on work on the windows.
thankyou
List updating / Redrawing
Posted by Legacy on 09/04/2002 12:00amOriginally posted by: Garfield
Does anyone know how to update the lists
display after added a new item outside of
the controls defined in CDualListManger?
For example, if you add a button that adds
an element to the listbox after the last
entry.
The problem is, after the item is added, it
does not show up in the list until after
an existing item is moved between the two
list (in either direction).
I have exhausted every method I can think of
in getting the contents to update. The last
item I tried was Invalidate() and visually
you can see the window flicker, but the list
itself does not update.
Any ideas?
Thanks
ReplyVery good example
Posted by Legacy on 01/31/2002 12:00amOriginally posted by: Frank
We had the same problem.
Reply
Nice!!! I find it!
Posted by Legacy on 12/26/2001 12:00amOriginally posted by: lie2me
ReplyExList
Posted by Legacy on 10/07/2001 12:00amOriginally posted by: Mike Philis
ReplyGreat !!
Posted by Legacy on 07/26/2001 12:00amOriginally posted by: flo
Hi...
And good job for your class ...
It's a good class .. and it seems that noone likes it ...
But i'm according with you when saying that it's useful...
And drag and drop is not necessary 'cause else the only thing that you could get is stop using the buttons ..
Thanx for this class...
Flo.
ReplyDueling Data Windows
Posted by Legacy on 04/18/2001 12:00amOriginally posted by: hans shapiro
I see NO drag & drop capability here to select in one of these dueling data windows and then drag to the other one and drop its load onto the other one. Also, be able to insert in the middle of the list of the dropee data window.
ReplyLoading, Please Wait ...