CListCtrl实现拖拽 效果

方法1:ide

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);
}this

////////////////////////////////////////code

方法2:blog

条目拖动

#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;
}索引