方法1:
void ClistOx::OnLvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult) { LPNMLISTVIEW pNMLV = reinterpret_cast
方法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; }