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