A Drag and Drop List Control

There are already several articles on CodeGuru that describe aspects of drag and drop in list and tree controls, particularly Dragging Items to Rearrange Rows by Wayne Berthin, and CreateDragImage for multiple selected items in CListCtrl by Frank Kobs. Unfortunately, none of these articles present a complete solution with working code, which is thus the purpose of this contribution.

This article includes a demo project, a CListCtrl derived class, and a release build EXE for a quick demonstration of the capabilities of the class. I don't intend the class to be all singing and dancing, but it is good enough for me to use in my current project. No doubt there are further enhancements that could be made it, so please be my guest.

The new class, CDragDropListCtrl, has the following features:

  • Supports dragging of single and multiple selections.
  • Potential drag targets are highlighted (selected) as the mouse moves over them.
  • The list control will scroll when you try to drag out of the top or bottom.
  • Horizontal mouse movement is ignored; if the mouse is to the left or right of the list control, dragging still occurs as though the mouse is over the control.
  • Works with LVS_EX_FULLROWSELECT style on or off.
  • Preserves the checked state of dragged items.
  • All code is encapsulated in the control—no changes are required to the parent class.

The class grew out of the original article by Wayne Berthin, but I've rewritten most of the code, and added a heap more. The CreateDragImageEx method is almost the same as that given by Frank Kobs, with a minor bug fix so that it works correctly when the LVS_EX_FULLROWSELECT style is not set.

To use the new class, first add the DragDropListCtrl.cpp and DragDropListCtrl.h files to your project. Then, add a list control to your dialog resource, and set the View style to Report. Use ClassWizard to add a variable for the list control. The Category for the variable should be Control, and the Variable type should be CDragDropListCtrl. Finally, add this line to the top of your dialog header file:

#include "DragDropListCtrl.h"

That's all there is to it!



Downloads

Comments

  • Not getting LButtonUp on single clicks

    Posted by yooper on 07/27/2009 10:56am

    I've implemented this control in one of my projects, and I'm seeing some slightly strange behavior. When I click my left mouse button on any item and release without dragging, I don't get the WM_ON_LBUTTONUP message. However, if I double-click on any item, I do get the WM_ON_LBUTTONUP message. Could this have something to do with the SetCapture()? Or is there something else I'm missing? Thanks!

    Reply
  • Problems with common controls v6 (XP and Vista style appearance)

    Posted by rjones on 01/07/2008 06:31pm

    There are several problems using this control with the new-style XP and Vista controls (common controls v6), including excessive flickering, autoscroll not working, and the drag image having an incorrect appearance. See the following thread for more details: http://www.codeguru.com/forum/showthread.php?t=442854 At present the thread describes a fix for the flickering and autoscroll problems, but there's still no fix for the odd-looking drag image. Can anyone find a fix for that?

    Reply
  • This is the fix for dragging to upper items

    Posted by jastek on 06/22/2005 01:07am

    All you have to do is change line #361 ---
    Original:
    356: void CDragDropListCtrl::DropItem()
    357: {
    358: RestorePrevDropItemState();
    359:
    360: // Drop after currently selected item.
    361: m_nDropIndex++;
    New:
    356: void CDragDropListCtrl::DropItem()
    357: {
    358: RestorePrevDropItemState();
    359:
    360: // Drop after currently selected item.
    361: if (m_nDropIndex > m_anDragIndexes[0]) m_nDropIndex++;

    Reply
  • Fix for using with itemdata for each item

    Posted by mecug on 03/16/2004 01:32am

    Before deleting drag item you must change value for lParam to NULL to prevent memory leak on droping item.
    
    void CDragDropListCtrl::DropItem()
    {
      ...
      // Change lParam data to NULL to prevent memory leak after DropItem
      lvItem.iItem=nDragIndex;
      lvItem.iSubItem=0;
      lvItem.mask=LVIF_PARAM;
      lvItem.lParam=(LPARAM)0L;
      SetItem(&lvItem);
    
      // Delete the original item.
      DeleteItem(nDragIndex);
      ...
    }
    
    Other fix: delete dcMem:
    
    CImageList* CDragDropListCtrl::CreateDragImageEx(LPPOINT lpPoint)
    {
     ...
     dcMem.SelectObject(pOldMemDCBitmap);
    
     // created with CreateCompatibleDC and you must be delete it 
     dcMem.DeleteDC();
     ...
    }

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

Top White Papers and Webcasts

  • With JRebel, developers get to see their code changes immediately, fine-tune their code with incremental changes, debug, explore and deploy their code with ease (both locally and remotely), and ultimately spend more time coding instead of waiting for the dreaded application redeploy to finish. Every time a developer tests a code change it takes minutes to build and deploy the application. JRebel keeps the app server running at all times, so testing is instantaneous and interactive.

  • Download the Information Governance Survey Benchmark Report to gain insights that can help you further establish business value in your Records and Information Management (RIM) program and across your entire organization. Discover how your peers in the industry are dealing with this evolving information lifecycle management environment and uncover key insights such as: 87% of organizations surveyed have a RIM program in place 8% measure compliance 64% cannot get employees to "let go" of information for …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds