CListCtrl实现拖拽效果

方法1:

void ClistOx::OnLvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult) { LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 CPoint ptItem, // ptAction, //事件发生的位置 ptImage;//移动位图的位置 NM_LISTVIEW *pnmListView = (NM_LISTVIEW *)pNMHDR; ASSERT(!m_bDragging); m_bDragging = TRUE; //获得选种的项的索引 m_iItemDrag = pnmListView-> iItem; //获得事件发生的位置 ptAction = pnmListView-> ptAction; //获得项的位置 GetItemPosition(m_iItemDrag, &ptItem); // ptItem is relative to (0,0) and not the view origin //获得视图原点位置 GetOrigin(&m_ptOrigin); ASSERT(m_pimageListDrag == NULL); m_pimageListDrag = CreateDragImage(m_iItemDrag, &ptImage); IMAGEINFO imageInfo; m_pimageListDrag->GetImageInfo(0,&imageInfo); m_ptHotSpot = ptAction - ptItem + m_ptOrigin; // calculate hotspot for the cursor m_pimageListDrag-> DragShowNolock(TRUE); // lock updates and show drag image m_pimageListDrag->Add(((HICON)LoadImage(NULL,_T("test.ico"),IMAGE_ICON,92,68,LR_LOADFROMFILE|LR_LOADTRANSPARENT))); //m_pimageListDrag-> SetDragCursorImage(2, m_ptHotSpot); // define the hot spot for the new cursor image m_pimageListDrag-> BeginDrag(0, m_ptHotSpot); //ptAction -= m_sizeDelta; m_pimageListDrag-> DragEnter(this,ptAction); //m_pimageListDrag-> DragMove(ptAction); // move image to overlap original icon SetCapture(); CRect rect; GetClientRect(&rect); ClientToScreen(&rect); ClipCursor(rect); //*pResult = 0; } void ClistOx::OnMouseMove(UINT nFlags, CPoint point) { int iItem; if (m_bDragging) { ASSERT(m_pimageListDrag != NULL); m_pimageListDrag-> DragMove(point); // move the image if ((iItem = HitTest(point )) != -1) { m_iItemDrop = iItem; m_pimageListDrag-> SetDragCursorImage(1, CPoint(4,4)); //m_pimageListDrag-> DragLeave(this); // unlock the window and hide drag image // if (lStyle == LVS_REPORT || lStyle == LVS_LIST) // { // lvitem.iItem = iItem; // lvitem.iSubItem = 0; // lvitem.mask = LVIF_STATE; // lvitem.stateMask = LVIS_DROPHILITED; // highlight the drop target // SetItem(&lvitem); //试图修改多种选中问题 // SetItemState(iItem, 0, LVIS_SELECTED|LVIS_FOCUSED); // } //point -= m_sizeDelta; //m_pimageListDrag-> DragEnter(this, point); // lock updates and show drag image } else m_pimageListDrag-> SetDragCursorImage(-1, CPoint(0,0)); } CListCtrl::OnMouseMove(nFlags, point); } void ClistOx::OnLButtonUp(UINT nFlags, CPoint point) { //当是Icon和smallIcon时用FindItem()方法,其余遍厉视图列表,确定要替换的项 CListCtrl::OnLButtonUp(nFlags, point); if (m_bDragging) // end of the drag operation { ASSERT(m_pimageListDrag != NULL); m_pimageListDrag-> DragLeave(this); m_pimageListDrag-> EndDrag(); delete m_pimageListDrag; m_pimageListDrag = NULL; //获得这两项的位置 if(m_iItemDrop==m_iItemDrag) { SetItemPosition(m_iItemDrag,CPoint(point + m_ptOrigin - m_ptHotSpot)); }else{ CPoint pointDrag,pointDrop; GetItemPosition(m_iItemDrop,&pointDrop); GetItemPosition(m_iItemDrag,&pointDrag); SetItemPosition(m_iItemDrag,pointDrop); SetItemPosition(m_iItemDrop,pointDrag); } m_bDragging = FALSE; Invalidate(); ::ReleaseCapture(); ClipCursor(NULL); } //CListCtrl::OnLButtonUp(nFlags, point); }

方法2:

条目拖动

#define MAX_DRAG_SIZE 128
#define MAX_DRAG_SIZE_2 (MAX_DRAG_SIZE/2)


添加数据成员

CImageList* m_pDragImage = NULL;//拖动时的图片
int m_nDragDrop, m_nDrag[MAX_DRAG_SIZE];//用于记录被拖动条目的index以及拖动到的位置


注:本文中仅以拖动1条为例,重在介绍方法,如果需要可作相应的扩展

响应消息LVN_BEGINDRAG, WM_MOUSEMOVE WM_LBUTTONUP
ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)

void CMyList::OnBegindrag(NMHDR *pNMHDR, LRESULT *pResult) { LPNMHEADER phdr = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; *pResult = 0; CPoint ptAction( pNMListView->ptAction ); for ( int i = 0; i < MAX_DRAG_SIZE; i++ ) { m_nDrag[i] = -1; } m_pDragImage = CreateDragImage( ptAction );//绘制图像 if ( m_pDragImage == NULL ) return; m_nDragDrop = -1; UpdateWindow(); CRect rcClient; GetClientRect( &rcClient ); ClientToScreen( &rcClient ); ClipCursor( &rcClient ); SetCapture(); SetFocus(); UpdateWindow(); m_pDragImage->DragEnter( this, ptAction ); *pResult = 0; } CImageList* CMyList::CreateDragImage(const CPoint& ptMouse) { CRect rcClient, rcOne, rcAll( 32000, 32000, -32000, -32000 ); int nIndex; if ( GetSelectedCount() == 0 ) return NULL; SetFocus(); GetClientRect( &rcClient ); int nCount = 0; for ( nIndex = -1 ; ( nIndex = GetNextItem( nIndex, LVNI_SELECTED ) ) >= 0 && MAX_DRAG_SIZE >= nCount; ) { m_nDrag[ nCount++ ] = nIndex; GetItemRect( nIndex, rcOne, LVIR_BOUNDS ); if ( rcOne.IntersectRect( &rcClient, &rcOne ) ) { rcAll.left = min( rcAll.left, rcOne.left ); rcAll.top = min( rcAll.top, rcOne.top ); rcAll.right = max( rcAll.right, rcOne.right ); rcAll.bottom = max( rcAll.bottom, rcOne.bottom ); } SetItemState( nIndex, 0, LVIS_FOCUSED ); } BOOL bClipped = rcAll.Height() > MAX_DRAG_SIZE; if ( bClipped ) { rcAll.left = max( rcAll.left, ptMouse.x - MAX_DRAG_SIZE_2 ); rcAll.right = max( rcAll.right, ptMouse.x + MAX_DRAG_SIZE_2 ); rcAll.top = max( rcAll.top, ptMouse.y - MAX_DRAG_SIZE_2 ); rcAll.bottom = max( rcAll.bottom, ptMouse.y + MAX_DRAG_SIZE_2 ); } CClientDC dcClient( this ); CBitmap bmAll, bmDrag; CDC dcAll, dcDrag; if ( ! dcAll.CreateCompatibleDC( &dcClient ) ) return NULL; if ( ! bmAll.CreateCompatibleBitmap( &dcClient, rcClient.Width(), rcClient.Height() ) ) return NULL; if ( ! dcDrag.CreateCompatibleDC( &dcClient ) ) return NULL; if ( ! bmDrag.CreateCompatibleBitmap( &dcClient, rcAll.Width(), rcAll.Height() ) ) return NULL; CBitmap *pOldAll = dcAll.SelectObject( &bmAll ); COLORREF crDrag = RGB( 250, 255, 250 ); dcAll.FillSolidRect( &rcClient, crDrag ); COLORREF crBack = GetBkColor(); SetBkColor( crDrag ); SendMessage( WM_PAINT, (WPARAM)dcAll.GetSafeHdc() ); SetBkColor( crBack ); CBitmap *pOldDrag = dcDrag.SelectObject( &bmDrag ); dcDrag.FillSolidRect( 0, 0, rcAll.Width(), rcAll.Height(), crDrag ); CRgn pRgn; if ( bClipped ) { CPoint ptMiddle( ptMouse.x - rcAll.left, ptMouse.y - rcAll.top ); pRgn.CreateEllipticRgn( ptMiddle.x - MAX_DRAG_SIZE_2, ptMiddle.y - MAX_DRAG_SIZE_2, ptMiddle.x + MAX_DRAG_SIZE_2, ptMiddle.y + MAX_DRAG_SIZE_2 ); dcDrag.SelectClipRgn( &pRgn ); } for ( nIndex = -1 ; ( nIndex = GetNextItem( nIndex, LVNI_SELECTED ) ) >= 0 ; ) { GetItemRect( nIndex, rcOne, LVIR_BOUNDS ); if ( rcOne.IntersectRect( &rcAll, &rcOne ) ) { dcDrag.BitBlt( rcOne.left - rcAll.left, rcOne.top - rcAll.top, rcOne.Width(), rcOne.Height(), &dcAll, rcOne.left, rcOne.top, SRCCOPY ); } } dcDrag.SelectObject( pOldDrag ); dcAll.SelectObject( pOldAll ); dcDrag.DeleteDC(); bmAll.DeleteObject(); dcAll.DeleteDC(); CImageList* pAll = new CImageList(); pAll->Create( rcAll.Width(), rcAll.Height(), ILC_COLOR16|ILC_MASK, 1, 1 ); pAll->Add( &bmDrag, crDrag ); bmDrag.DeleteObject(); pAll->BeginDrag( 0, ptMouse - rcAll.TopLeft() ); return pAll; } void CMyList::OnMouseMove(UINT nFlags, CPoint point)//移动的视觉效果 { // TODO: 在此添加消息处理程序代码和/或调用默认值 int nHit = HitTest( point ); if ( m_pDragImage != NULL ) { m_pDragImage->DragMove( point ); if ( nHit != m_nDragDrop ) { CImageList:ragShowNolock( FALSE ); if ( m_nDragDrop >= 0 ) SetItemState( m_nDragDrop, 0, LVIS_DROPHILITED ); m_nDragDrop = nHit; if ( m_nDragDrop >= 0 ) SetItemState( m_nDragDrop, LVIS_DROPHILITED, LVIS_DROPHILITED ); UpdateWindow(); CImageList:ragShowNolock( TRUE ); } } CListCtrl::OnMouseMove(nFlags, point); } void CMyList::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if ( m_pDragImage == NULL ) { CListCtrl::OnLButtonUp( nFlags, point ); return; } ClipCursor( NULL ); ReleaseCapture(); m_pDragImage->DragLeave( this ); m_pDragImage->EndDrag(); delete m_pDragImage; m_pDragImage = NULL; if ( m_nDragDrop >= 0 ) { SetItemState( m_nDragDrop, 0, LVIS_DROPHILITED ); /*由于本类中只是加了拖动的效果和记录拖动的相关信息,当拖动结束以后并没有实际效果。故需要传递消息 在其父窗口中进行拖动的实际处理*/ NM_LISTVIEW pNotify; pNotify.hdr.hwndFrom = GetSafeHwnd(); pNotify.hdr.idFrom = GetDlgCtrlID(); pNotify.hdr.code = HDN_ENDDRAG; pNotify.iItem = m_nDragDrop;//拖动到的index pNotify.lParam = (LPARAM)m_nDrag;//被拖动的Item GetOwner()->SendMessage( WM_NOTIFY, pNotify.hdr.idFrom, (LPARAM)&pNotify ); } }

在其listbox的父窗口中进行以下处理
ON_NOTIFY(HDN_ENDDRAG, IDC_LIST, OnEnddragList)//IDC_LIST为list控件的ID

 

void CDlgXX::OnEnddragList(NMHDR *pNMHDR, LRESULT *pResult) { NM_LISTVIEW* pNotify = (NM_LISTVIEW *)pNMHDR; int* pBegin = (int*)pNotify->lParam; int nEnd = pNotify->iItem; m_bChange = TRUE; CString strTmp; BOOL bAhead = pBegin[0] > nEnd ? TRUE : FALSE; for ( int i = 0; i < MAX_DRAG_SIZE && pBegin[i] >= 0; i++ ) { if ( pBegin[i] == nEnd ) { nEnd++; continue; } strTmp = m_ctrlList.GetItemText( pBegin[i], 0 ); m_ctrlList.DeleteItem( pBegin[i] ); /*向上托第一条插在nEnd之前,向下托第一条插在nEnd之后,所拖动的条目保持原来的顺序*/ if ( bAhead ) { if ( pBegin[i] < nEnd ) nEnd--; for ( int j = i + 1; j < MAX_DRAG_SIZE && pBegin[j] >= 0; j++) { if ( pBegin[j] <= nEnd ) pBegin[j]--; } m_ctrlList.InsertItem( nEnd, strTmp ); nEnd++; } else { if ( pBegin[i] >= nEnd ) nEnd++; for ( int j = i + 1; j < MAX_DRAG_SIZE && pBegin[j] >= 0; j++) if ( pBegin[j] <= nEnd ) pBegin[j]--; m_ctrlList.InsertItem( nEnd, strTmp ); } } *pResult = 0; }

你可能感兴趣的:(CListCtrl实现拖拽效果)