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; }
Downloads
Download source (same as above, but with proper formatting) – 1 Kb