#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::DragShowNolock( 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::DragShowNolock( 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;
}
#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::DragShowNolock( 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::DragShowNolock( 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;
}