Click here to Skip to main content
15,881,559 members
Articles / Desktop Programming / MFC
Article

Drag and Drop Listbox Items

Rate me:
Please Sign up or sign in to vote.
4.97/5 (12 votes)
1 Dec 2005CPOL2 min read 87.6K   3.4K   38   10
Rearrange listbox items using drag and drop without OLE.

Drag and Drop Listbox

Introduction

This listbox class demonstrates how to rearrange listbox items using Drag and Drop without the overhead of OLE. The advantage of this method is that you don't have to create bulky global memory handles to simply move data within the same window in the same application. The concept is very simple: keep track of the item that is being dragged, indicate where the drop will be when the user is dragging the item around, and finally, insert the item in its new location once the user releases the mouse button.

To accomplish this task, you will need to catch three messages for your listbox window: WM_LBUTTONDOWN, WM_MOUSEMOVE, and WM_LBUTTONUP.

The WM_LBUTTONDOWN handler method simply initialized the drag and drop process by finding the item that the user clicked on.

void CDragAndDropListBox::OnLButtonDown(UINT nFlags, CPoint point)
{
   CListBox::OnLButtonDown(nFlags, point);

   //clear all the flags
   m_MovingIndex = LB_ERR;
   m_MoveToIndex = LB_ERR;
   m_Captured = FALSE;
   m_Interval = 0;
   
   BOOL Outside;
   //find the item that they want to drag
   //and keep track of it. Later in the mouse move
   //we will capture the mouse if this value is set
   int Index = ItemFromPoint(point,Outside);
   if (Index != LB_ERR && !Outside)
   {
      m_MovingIndex = Index;
      SetCurSel(Index);
   }
}

The WM_WMMOUSEMOVE handler method does three things. One is to capture the mouse if it hasn't done so. Two is to scroll the listbox if the user has dragged the mouse above or below the listbox window (it does this with the help of timers). And finally, to draw a line above the item where the dragged item will be dropped, it also keeps track of the item's index value so that WM_LBUTTONUP does not have to find the information again.

void CDragAndDropListBox::OnMouseMove(UINT nFlags, CPoint point)
{
   CListBox::OnMouseMove(nFlags, point);
   if (nFlags & MK_LBUTTON)
   {
      if (m_MovingIndex != LB_ERR && !m_Captured)
      {
         SetCapture();
         m_Captured = TRUE;
      }
      BOOL Outside;
      int Index = ItemFromPoint(point,Outside);
      //if they our not on a particular item
      if (Outside)
      {
         CRect ClientRect;
         GetClientRect(&ClientRect);

         //if they are still within the listbox window, then
         //simply select the last item as the drop point
         //else if they are outside the window then scroll the items
         if (ClientRect.PtInRect(point))
         {
            KillTimer(TID_SCROLLDOWN);
            KillTimer(TID_SCROLLUP);
            m_Interval = 0;
            //indicates that the user wants to drop the item
            //at the end of the list
            Index = LB_ERR;
            Outside = FALSE;
         }
         else
         {
            DoTheScrolling(point,ClientRect);
         }
      }
      else
      {
         KillTimer(TID_SCROLLDOWN);
         KillTimer(TID_SCROLLUP);
         m_Interval = 0;
      }
      
      if (Index != m_MoveToIndex && !Outside)
      {
         DrawTheLines(Index);
      }
   }
}

Next, the WM_LBUTTONUP message handler will do the actual drop operation. It first checks to make sure that there was a item being dragged to begin with. Next it checks to make sure that the button was released within the listbox window. If it wasn't then there is nothing to do. If on the other hand it was released within the window, then simply insert the item into the listbox at the index indicated by the WM_MOUSEMOVE handler.

void CDragAndDropListBox::OnLButtonUp(UINT nFlags, CPoint point)
{
   if (m_MovingIndex != LB_ERR && m_Captured)
   {
      KillTimer(TID_SCROLLDOWN);
      KillTimer(TID_SCROLLUP);
      m_Interval = 0;
      m_Captured = FALSE;
      ReleaseCapture();

      CRect Rect;
      GetClientRect(&Rect);
      //if they are still within the listbox window
      if (Rect.PtInRect(point))
      {
         InsertDraggedItem();
      }
      else
      {
         Invalidate();
         UpdateWindow();
      }
      m_MovingIndex = LB_ERR;
      m_MoveToIndex = LB_ERR;
   }

   CListBox::OnLButtonUp(nFlags, point);
}

Using the code

To use this class, simply attach a variable (subclass) to the listbox control on your window, and then change the variable from CListBox to CDragAndDropListBox. That's all.

// CDragDropListBoxSampleDlg dialog
class CDragDropListBoxSampleDlg : public CDialog
{
......

// Implementation
protected:
   CDragAndDropListBox  m_ListBox;
   
......
};

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
Ali Rafiee has been developing windows applications using C++ since 1991, and he hasn't looked back since. Ali has been a software development consultant for must of his career, but he has finally settled down and has been working for an educational software company since 2000. While he is not working, he is either learning C#, flying airplanes, playing with his daughter, or answering peoples question on newsgroups, he finds that to be a great learning tool for himself.

Ali is also a Microsoft Visual C++ MVP.

Comments and Discussions

 
GeneralHi Can we use this as part of the application we are developing Pin
PSVN Roy13-Oct-10 6:21
PSVN Roy13-Oct-10 6:21 
GeneralRe: Hi Can we use this as part of the application we are developing Pin
Ali Rafiee13-Oct-10 6:28
Ali Rafiee13-Oct-10 6:28 
GeneralAdaptation to list of a combobox Pin
epitalon28-Jan-09 4:04
epitalon28-Jan-09 4:04 
GeneralExactly what I needed! Pin
Cris Moore5-Mar-06 7:48
Cris Moore5-Mar-06 7:48 
GeneralCDragListBox... Pin
bolivar1235-Dec-05 10:28
bolivar1235-Dec-05 10:28 
GeneralRE Pin
Ali Rafiee5-Dec-05 10:40
Ali Rafiee5-Dec-05 10:40 
GeneralRe: CDragListBox... Pin
Ali Rafiee5-Dec-05 10:53
Ali Rafiee5-Dec-05 10:53 
GeneralRe: CDragListBox... Pin
HQH20-Jun-07 14:26
HQH20-Jun-07 14:26 
GeneralRe: CDragListBox... Pin
HQH20-Jun-07 21:00
HQH20-Jun-07 21:00 
GeneralRe: CDragListBox... Pin
Ali Rafiee21-Jun-07 7:01
Ali Rafiee21-Jun-07 7:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.