A Dual ListBox Selection Manager

I have seen many applications that provide the user with the ability to select an item from one list and put it into another. One example is the NT User manager group memberships screen. This is commonly done by placing two listboxes side by side. Then buttons are generally used to add, add all, remove, remove all and to move items up and down in the list of choosen items. Here's a screen shot from my demo application:

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 Kb
Download source - 9 Kb


Comments

  • Add Clear and Refill members

    Posted by t.buys on 10/06/2005 06:15am

    In 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();
    	}
    }
    

    Reply
  • Update for XP style manifest and flicker

    Posted by t.buys on 09/29/2005 09:51am

    I 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 function
    if (!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
    FillListboxes(&SelectedArray, FALSE, TRUE);
    
    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;
    }
    

    Reply
  • Good, but not complete

    Posted by Legacy on 01/20/2004 12:00am

    Originally 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.

    Reply
  • ClistControll

    Posted by Legacy on 03/03/2003 12:00am

    Originally posted by: javaid hussain

    Hell,
    i 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

    Reply
  • List updating / Redrawing

    Posted by Legacy on 09/04/2002 12:00am

    Originally 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

    Reply
  • Very good example

    Posted by Legacy on 01/31/2002 12:00am

    Originally posted by: Frank

    We had the same problem.

    Reply
  • Nice!!! I find it!

    Posted by Legacy on 12/26/2001 12:00am

    Originally posted by: lie2me

    very very niec!!!
    

    Reply
  • ExList

    Posted by Legacy on 10/07/2001 12:00am

    Originally posted by: Mike Philis

    Do you need an advanced list control? Check this out:
    
    http://www.exontrol.com/sg.jsp?content=products/exlist

    Mike
    www.exontrol.com

    Reply
  • Great !!

    Posted by Legacy on 07/26/2001 12:00am

    Originally 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.

    Reply
  • Dueling Data Windows

    Posted by Legacy on 04/18/2001 12:00am

    Originally 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.

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The latest release of SugarCRM's flagship product gives users new tools to build extraordinary customer relationships. Read an in-depth analysis of SugarCRM's enhanced ability to help companies execute their customer-facing initiatives from Ovum, a leading technology research firm.

  • Ever-increasing workloads and the challenge of containing costs leave companies conflicted by the need for increased processing capacity while limiting physical expansion. Migration to HP's new generation of increased-density rack-and-blade servers can address growing demands for compute capacity while reducing costly sprawl. Sponsored by: HP and Intel® Xeon® processors Intel, the Intel logo, and Xeon Inside are trademarks of Intel Corporation in the U.S. and/or other countries. HP is the sponsor …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds