CreateDragImage for multiple selected items in CListCtrl
Posted
by Frank Kobs
on December 21st, 1999

Environment: VC6 SP2, NT4 SP4
Currently the CreateDragImage method from CListCtrl only supports the generation of drag images of a single selected item (at least I didn't found an alternative in the Win API). Inspired by an article from Pel K Txnder I found one way to create drag images for multiple selections.
The trick is to create a bitmap in a memory dc and paint the drag image from each selected item into it. This bitmap is added to the drag imagelist. The code enhances a derived CListCtrl (CListCtrlEx) with the method CreateDragImageEx. However, it should also work with a few modifications without subclassing the CListCtrl.
CImageList *CListCtrlEx::CreateDragImageEx( LPPOINT lpPoint )
{
CRect cSingleRect;
CRect cCompleteRect( 0,0,0,0 );
int nIdx;
BOOL bFirst = TRUE;
//
// Determine the size of the drag image
//
POSITION pos = GetFirstSelectedItemPosition();
while (pos)
{
nIdx = GetNextSelectedItem( pos );
GetItemRect( nIdx, cSingleRect, LVIR_BOUNDS );
if (bFirst)
{
// Initialize the CompleteRect
GetItemRect( nIdx, cCompleteRect, LVIR_BOUNDS );
bFirst = FALSE;
}
cCompleteRect.UnionRect( cCompleteRect, cSingleRect );
}
//
// Create bitmap in memory DC
//
CClientDC cDc(this);
CDC cMemDC;
CBitmap cBitmap;
if(!cMemDC.CreateCompatibleDC(&cDc))
return NULL;
if(!cBitmap.CreateCompatibleBitmap(&cDc, cCompleteRect.Width(), cCompleteRect.Height()))
return NULL;
CBitmap* pOldMemDCBitmap = cMemDC.SelectObject( &cBitmap );
// Here green is used as mask color
cMemDC.FillSolidRect(0,0,cCompleteRect.Width(), cCompleteRect.Height(), RGB(0, 255, 0));
//
// Paint each DragImage in the DC
//
CImageList *pSingleImageList;
CPoint cPt;
pos = GetFirstSelectedItemPosition();
while (pos)
{
nIdx = GetNextSelectedItem( pos );
GetItemRect( nIdx, cSingleRect, LVIR_BOUNDS );
pSingleImageList = CreateDragImage( nIdx, &cPt);
if (pSingleImageList)
{
pSingleImageList->DrawIndirect( &cMemDC,
0,
CPoint( cSingleRect.left-cCompleteRect.left,
cSingleRect.top-cCompleteRect.top ),
cSingleRect.Size(),
CPoint(0,0));
delete pSingleImageList;
}
}
cMemDC.SelectObject( pOldMemDCBitmap );
//
// Create the imagelist with the merged drag images
//
CImageList* pCompleteImageList = new CImageList;
pCompleteImageList->Create( cCompleteRect.Width(),
cCompleteRect.Height(),
ILC_COLOR | ILC_MASK, 0, 1);
// Here green is used as mask color
pCompleteImageList->Add(&cBitmap, RGB(0, 255, 0));
cBitmap.DeleteObject();
//
// as an optional service:
// Find the offset of the current mouse cursor to the imagelist
// this we can use in BeginDrag()
//
if ( lpPoint )
{
CPoint cCursorPos;
GetCursorPos( &cCursorPos );
ScreenToClient( &cCursorPos );
lpPoint->x = cCursorPos.x - cCompleteRect.left;
lpPoint->y = cCursorPos.y - cCompleteRect.top;
}
return( pCompleteImageList );
}
Sample usage:
void CDialogWhichUsesListCtrl::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
POINT pt;
m_pDragImage = m_ctlList.CreateDragImageEx( &pt );
m_pDragImage->BeginDrag( 0, pt );
m_pDragImage->DragEnter( GetDesktopWindow(), pNMListView->ptAction);
SetCapture();
*pResult = 0;
}

Comments
How about custom drag image?
Posted by Legacy on 01/26/2004 12:00amOriginally posted by: Steven
Hi everybody,
Vladimir's comment only partly solves my problem. You see, I want to perform a drag&drop operation, but want the drag image to be a custom string. The strng would be a composition of 4 columns in the list control, but I don't want the unnecessry space between the columns in the drag image. Can anyone help me with this???
ReplyGreat! ... but need little repair for LVS_EX_FULLROWSELECT
Posted by Legacy on 11/05/2003 12:00amOriginally posted by: Vladimir
-
ReplySorry, but this code DOES NOT support multiple selected items...
Posted by PatrikE on 09/09/2005 07:07amIt is a little bit misleading to post that code under this article, since one would expect code here that DOES support that feature. Besides: It also does NOT display the icon of the selected row. This reply is intended to inform readers of Vladimirs post about the capabilities of his code and not to bash him in any way.
ReplyModification for Owner drawn List Views
Posted by Legacy on 02/21/2000 12:00amOriginally posted by: Maurizio Maccani
ReplyFunctions undefined...
Posted by Legacy on 02/17/2000 12:00amOriginally posted by: Daniel Larocque
I would like to use your code but I can't get it to compile.
Where is GetFirstSelectedItemPosition (...) supposed to be defined?
Where is DrawIndirect (...) supposed to be defined?
Reply