CListCtrl의 Drag & Drop

- CListCtrl의 row를 Drag & Drop 하는 경우를 말한다.
- 드래그 시작 시에 LVN_BEGINDRAG가, 드래그 중에 WM_MOUSEMOVE가, 드래그가 끝날 때 WM_LBUTTONUP이 발생한다
- 각 상황에 대한 처리 방법은 아래의 예제 코드를 참조

void CMG_HW1Dlg::OnBegindragListEditing(NMHDR* pNMHDR, LRESULT* pResult)
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	OnBegindrag(&m_listEditing, pNMHDR);

	*pResult = 0;
}

void CMG_HW1Dlg::OnBegindrag(CListCtrl *list, NMHDR *pNMHDR)
{
	if( list->GetSelectedCount() <= 0 )
		return;

	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	m_bDrag = TRUE;
	m_hDragWnd = list;

	CPoint pt;	
	
	CPoint hotSpotPt(pNMListView->ptAction);
	
	m_pImageList = CreateDragImageEx(list, &pt);

	if( m_pImageList == NULL )
		return;

	hotSpotPt -= pt;

	m_pImageList->BeginDrag(0, hotSpotPt);

	m_pImageList->DragEnter(NULL, pNMListView->ptAction);

	m_pImageList->DragShowNolock(true);

	SetCapture();
}

void CMG_HW1Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
	if( m_bDrag && m_hDragWnd )
	{
		CPoint screenPt(point);
		ClientToScreen(&screenPt);

		m_pImageList->DragMove(screenPt);

		CWnd * hDropWnd = WindowFromPoint(screenPt);

		CRect winRect;
		GetWindowRect(&winRect);
		BOOL bOutOfWindow = !(winRect.PtInRect(screenPt));

		if( m_hDragWnd == &m_listRegistered && hDropWnd == &m_listFtpFile )
			SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
		else if( m_hDragWnd == &m_listFtpFile && hDropWnd == &m_listRegistered )
			SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
		else if( m_hDragWnd == &m_listFtpFile && hDropWnd == &m_listEditing )
			SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
		else if( m_hDragWnd == &m_listEditing && hDropWnd == &m_listFtpFile )
			SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
		else if( m_hDragWnd == &m_listRegistered && bOutOfWindow == TRUE )
			SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
		else
			SetCursor(AfxGetApp()->LoadStandardCursor(IDC_NO));
	}

	CDialog::OnMouseMove(nFlags, point);
}

void CMG_HW1Dlg::OnLButtonUp(UINT nFlags, CPoint point)
{
	if( m_bDrag && m_hDragWnd )
	{
		ReleaseCapture();
		m_pImageList->DragLeave(NULL);
		m_pImageList->EndDrag();

		CPoint screenPt(point);
		ClientToScreen(&screenPt);
		CWnd * hDropWnd = WindowFromPoint(screenPt);
		CRect winRect;
		GetWindowRect(&winRect);
		BOOL bOutOfWindow = !(winRect.PtInRect(screenPt));

		if( m_hDragWnd == &m_listRegistered && hDropWnd == &m_listFtpFile )
			OnButtonUpload();
		else if( m_hDragWnd == &m_listFtpFile && hDropWnd == &m_listRegistered )
			OnButtonDownload();
		else if( m_hDragWnd == &m_listFtpFile && hDropWnd == &m_listEditing )
			OnButtonEdit();
		else if( m_hDragWnd == &m_listEditing && hDropWnd == &m_listFtpFile )
			OnButtonApplyedit();
		else if( m_hDragWnd == &m_listRegistered && bOutOfWindow == TRUE )
			OnButtonUnregister();

		m_bDrag = FALSE;
		m_hDragWnd = NULL;

		delete m_pImageList;
		m_pImageList = NULL;

	}

	CDialog::OnLButtonUp(nFlags, point);
}

//////////////////////////////////////////////////////////////////////////
// Copied by KpsFtp
CImageList * CMG_HW1Dlg::CreateDragImageEx(CListCtrl *pList, LPPOINT lpPoint)
{
	if (pList->GetSelectedCount() <= 0)
		return NULL; 

	CRect rectSingle;
	CRect rectComplete(0,0,0,0);

	// Determine List Control Client width size
	pList->GetClientRect(rectSingle);

	int nWidth  = rectSingle.Width();

	// Start and Stop index in view area

	int nIndex = pList->GetTopIndex() - 1;
	int nBottomIndex = pList->GetTopIndex() + pList->GetCountPerPage() - 1;
	if (nBottomIndex > (pList->GetItemCount() - 1))
	nBottomIndex = pList->GetItemCount() - 1;

	// Determine the size of the drag image (limit for rows visibled and Client width)
	while ((nIndex = pList->GetNextItem(nIndex, LVNI_SELECTED)) != -1)
	{
		if (nIndex > nBottomIndex)
			break;

		pList->GetItemRect(nIndex, rectSingle, LVIR_BOUNDS);

		if (rectSingle.left < 0)
			rectSingle.left = 0;

		if (rectSingle.right > nWidth)
			rectSingle.right = nWidth;

		rectComplete.UnionRect(rectComplete, rectSingle);

	}

	CClientDC dcClient(this);

	CDC dcMem;
	CBitmap Bitmap;

	if (!dcMem.CreateCompatibleDC(&dcClient))
		return NULL;

	if (!Bitmap.CreateCompatibleBitmap(&dcClient, rectComplete.Width(), rectComplete.Height()))
		return NULL;

	CBitmap *pOldMemDCBitmap = dcMem.SelectObject(&Bitmap);

	// Use green as mask color
	dcMem.FillSolidRect(0, 0, rectComplete.Width(), rectComplete.Height(), RGB(0,255,0));

	// Paint each DragImage in the DC
	nIndex = pList->GetTopIndex() - 1;

	while ((nIndex = pList->GetNextItem(nIndex, LVNI_SELECTED)) != -1)
	{
		if (nIndex > nBottomIndex)
			break;

		CPoint pt;

		CImageList* pSingleImageList = pList->CreateDragImage(nIndex, &pt);

		if (pSingleImageList)
		{
			pList->GetItemRect(nIndex, rectSingle, LVIR_BOUNDS);

			pSingleImageList->Draw( &dcMem, 0, CPoint(rectSingle.left - rectComplete.left, rectSingle.top - rectComplete.top), ILD_MASK);
			pSingleImageList->DeleteImageList();
			delete pSingleImageList;
		}
	}

	dcMem.SelectObject(pOldMemDCBitmap);

	CImageList* pCompleteImageList = new CImageList;
	pCompleteImageList->Create(rectComplete.Width(), rectComplete.Height(), ILC_COLOR | ILC_MASK, 0, 1);
	pCompleteImageList->Add(&Bitmap, RGB(0, 255, 0)); // Green is used as mask color

	Bitmap.DeleteObject();
	if (lpPoint)
	{
		lpPoint->x = rectComplete.left;

		lpPoint->y = rectComplete.top;
	}

	return pCompleteImageList;

}

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Heart