Pictrue Control和TreeCtrl的拖动

Pictrue Control实际上就是CStatic,它的动态创建过程如下:

	m_Static.Create(_T(""), WS_VISIBLE|WS_CHILD|SS_BITMAP|SS_CENTERIMAGE, CRect(200,200,300,300), this);
	HBITMAP hBitMap = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP_Black));
	m_Static.SetBitmap(hBitMap);

然后就是响应鼠标的几个动作:

按下左键:

void CXXXDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	CRect	rectPic;
	POINT	ptPut 	= point;

	//GetDlgItem(IDC_STATIC_Image1)->GetWindowRect(rectPic);
	m_Static.GetWindowRect(rectPic);

	ClientToScreen(&ptPut);
	if(rectPic.PtInRect(ptPut))
	{
		CBitmap		bitmapTemp, *pOldBitmap;
		CDC			*pDC	= m_Static.GetDC();
		CDC *pMemDC	= new CDC;

		//创建位图内存
		bitmapTemp.CreateCompatibleBitmap(pDC, rectPic.Width(), rectPic.Height());
		pMemDC->CreateCompatibleDC(pDC);
		pOldBitmap	= pMemDC->SelectObject(&bitmapTemp);
		pMemDC->BitBlt(0, 0, rectPic.Width(), rectPic.Height(), pDC, 0, 0, SRCCOPY);
		pMemDC->SelectObject(pOldBitmap);
		delete	pMemDC;
		ReleaseDC(pDC);

		m_bIsLButtonDown	= TRUE;

		m_ptOffset.x	= ptPut.x-rectPic.left;
		m_ptOffset.y	= ptPut.y-rectPic.top;

		m_imgDrag.DeleteImageList();
		m_imgDrag.Create(rectPic.Width(), rectPic.Height(), ILC_COLOR32|ILC_MASK, 0, 1);
		m_imgDrag.Add(&bitmapTemp, RGB(0, 0, 0));
		m_imgDrag.BeginDrag(0, m_ptOffset);
		m_imgDrag.DragEnter(NULL, ptPut);

		SetCapture();
	}

	CDialog::OnLButtonDown(nFlags, point);
}

鼠标移动:

void CXXXXDlg::OnMouseMove(UINT nFlags, CPoint point)
{
	if(m_bIsLButtonDown)
	{
		CRect		rtClient, rtPicture;

		m_ptMove	= point;

		//GetDlgItem(IDC_STATIC_Image1)->GetWindowRect(rtPicture);
		m_Static.GetWindowRect(rtPicture);

		GetClientRect(rtClient);
		ClientToScreen(&rtClient);
		ClientToScreen(&m_ptMove);
		if(rtClient.left>m_ptMove.x-m_ptOffset.x)
			m_ptMove.x	= rtClient.left+m_ptOffset.x;
		if(rtClient.top>m_ptMove.y-m_ptOffset.y)
			m_ptMove.y	= rtClient.top+m_ptOffset.y;
		if(rtClient.right-rtPicture.Width()<m_ptMove.x-m_ptOffset.x)
			m_ptMove.x	= rtClient.right-rtPicture.Width()+m_ptOffset.x;
		if(rtClient.bottom-rtPicture.Height()<m_ptMove.y-m_ptOffset.y)
			m_ptMove.y	= rtClient.bottom-rtPicture.Height()+m_ptOffset.y;

		CImageList::DragMove(m_ptMove);
	}

	CDialog::OnMouseMove(nFlags, point);
}

左键弹起:

void CXXXXDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
	if(m_bIsLButtonDown)
	{
		CRect rectPic;
		ScreenToClient(&m_ptMove);
		m_Static.GetWindowRect(rectPic);
		m_Static.MoveWindow(m_ptMove.x-m_ptOffset.x, m_ptMove.y-m_ptOffset.y, rectPic.Width(), rectPic.Height());
		m_bIsLButtonDown	= FALSE;
		
		CImageList::DragLeave(this);
		CImageList::EndDrag();
		ReleaseCapture();
		m_Static.Invalidate();

	}

	CDialog::OnLButtonUp(nFlags, point);
}


TreeCtrl也是一样,同样是响应鼠标的几个动作,只不过麻烦一点:

按下左键:

void CDragDropTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
	SetFocus();
	do
	{	
		HTREEITEM hItem = HitTest(point,&nFlags);
		if( nFlags & TVHT_ONITEMBUTTON )
		{	
			// Check if any child present
			if(!ItemHasChildren(hItem))
			{
				break;
			}
			CTreeCtrl::OnLButtonDown(nFlags,point);
			break;
		}
		if( NULL == hItem )
		{
			break;
		}
		if( NULL == GetParentItem(hItem) )
		{
			break;
		}
		unsigned short shKeyState = GetKeyState(VK_CONTROL);
		shKeyState >>= 15;//get high-order bit
		if( shKeyState == 1 )// key down
		{ 
			OnControlKeyPress(hItem);
			break;
		} 
		else
		{
			if( m_vSelItem.size() == 0 )
			{
				SetItemState(hItem,TVIS_SELECTED,TVIS_SELECTED);
				m_vSelItem.push_back(hItem);
				break;
			}
			shKeyState = GetKeyState(VK_SHIFT);
			shKeyState >>= 15;
			if( shKeyState == 1 )
			{
				OnShiftKeyPress(hItem);
				break;
			}
		}
		m_hLastSelItem = hItem;
		if( m_vSelItem.size() == 1 )
		{
			ClearSelection();
			SetItemState(m_hLastSelItem,TVIS_SELECTED,TVIS_SELECTED);
			m_vSelItem.push_back(m_hLastSelItem);
		}
	}while(false);
}
其中OnShiftKeyPress是响应shift按键,用来添加一组item,实现如下:

void CDragDropTreeCtrl::OnShiftKeyPress(HTREEITEM hCurItem)
{
	if( m_vSelItem.size() > 0 )
	{
		if( !IsInTheSameLevel(hCurItem) )
		{
			return;
		}
	}
	HTREEITEM hItemFrom = m_vSelItem[0];
	SetItemState(hCurItem,TVIS_SELECTED,TVIS_SELECTED);
	SelectItems(hItemFrom,hCurItem);
}

BOOL CDragDropTreeCtrl::IsInTheSameLevel(HTREEITEM hItem)
{
	BOOL bInTheSameLevel = TRUE;
	SEL_ITEM_LIST::iterator itr;
	for( itr = m_vSelItem.begin(); itr != m_vSelItem.end(); ++itr )
	{
		if( GetParentItem(hItem) != GetParentItem(*itr) )
		{
			bInTheSameLevel = FALSE;
		}
	}
	return bInTheSameLevel;
}

SelectItems用来将item加入链表或从链表清除:

void CDragDropTreeCtrl::SelectItems(HTREEITEM hItemFrom,HTREEITEM hItemTo)
{
	RECT FromRect;
	GetItemRect(hItemFrom,&FromRect,FALSE);
	RECT ToRect;
	GetItemRect(hItemTo,&ToRect,FALSE);
	HTREEITEM hTemp;
	if( FromRect.top > ToRect.top )
	{
		hTemp = hItemFrom;
		hItemFrom = hItemTo;
		hItemTo = hTemp;
	}
	ClearSelection();
	hTemp = hItemFrom;
	while(1)
	{
		SetItemState(hTemp,TVIS_SELECTED,TVIS_SELECTED);
		m_vSelItem.push_back(hTemp);
		if( hTemp ==  hItemTo )
		{
			break;
		}
		hTemp = GetNextVisibleItem(hTemp);
	}
}

void CDragDropTreeCtrl::ClearSelection()
{
	int nSelItemCount = m_vSelItem.size();
	for( int nIdx = 0; nIdx < nSelItemCount; ++nIdx)
	{
		SetItemState(m_vSelItem[nIdx],0,TVIS_SELECTED);//全部置0
	}
	m_vSelItem.clear();
}


OnControlKeyPress用来响应Ctrl按键,用来逐个添加或删除item

void CDragDropTreeCtrl::OnControlKeyPress(HTREEITEM hCurItem)
{
	if( m_vSelItem.size() > 0 )
	{
		if( !IsInTheSameLevel(hCurItem) )
		{
			return;
		}
	}

	int nState = (TVIS_SELECTED == GetItemState(hCurItem,TVIS_SELECTED))?0:TVIS_SELECTED;
	SetItemState(hCurItem,nState,TVIS_SELECTED);
	if( 0 == nState )
	{
		RemoveFromSelectionList(hCurItem);
	}
	else
	{
		m_vSelItem.push_back(hCurItem);
	}
}

void CDragDropTreeCtrl::RemoveFromSelectionList(HTREEITEM hItem)
{
	SEL_ITEM_LIST::iterator itr;
	for( itr = m_vSelItem.begin(); itr != m_vSelItem.end(); ++itr )
	{
		if( (*itr) == hItem )
		{
			m_vSelItem.erase(itr);
			break;
		}
	}  
}
还需要在鼠标点击空白处时取消选中:

void CDragDropTreeCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult)
{
	//if click is not on any item clear all the selection
	int nSelItemCount = m_vSelItem.size();
	for( int nIdx = 0; nIdx < nSelItemCount; ++nIdx)
	{
		SetItemState(m_vSelItem[nIdx],0,TVIS_SELECTED);//全部置0
	}
	m_vSelItem.clear();    
}


移动鼠标:

void CDragDropTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	if( ::DragDetect(m_hWnd,point) )
	{
		OnDrag(point);
	}
	CTreeCtrl::OnMouseMove(nFlags,point);
} 

void CDragDropTreeCtrl::OnDrag(CPoint point)
{
	if( m_vSelItem.size() ==  0 )//没有拖动item
	{
		return;
	}
	m_bDragging = TRUE;
	UINT nFlags;
	HTREEITEM hItem = HitTest(point,&nFlags);

	m_pImageList = CreateDragImageEx();

	ASSERT (m_pImageList != NULL);

	if (m_pImageList != NULL)
	{
		CRect rect;
		GetItemRect (hItem, rect, TRUE);
		POINT pt;
		pt.x = rect.left+5;
		pt.y = rect.top+5;

		ClientToScreen ( &pt ) ;
		m_pImageList->BeginDrag (0,CPoint(-5,-5));
		m_pImageList->DragEnter (NULL, pt);    
		SetCapture();
		int nEventListenerCount = m_vEventListener.size();
		for( int nEventListenerIdx = 0; nEventListenerIdx < nEventListenerCount; ++nEventListenerIdx )
		{
			m_vEventListener[nEventListenerIdx]->OnDrag();//外部接口实现
		}
	}
}
其中的关键步骤在于移动中对item的绘制:

CImageList* CDragDropTreeCtrl::CreateDragImageEx()
{
	// Find the bounding rectangle of all the selected items
	CRect		rectBounding; // Holds rectangle bounding area for bitmap
	CRect		rectFirstItem; // Holds first item's height and width
	CRect		rectTextArea;  // Holds text area of image
	
	int			nNumSelected; // Holds total number of selected items
	HTREEITEM	hItem;
	CClientDC	DraggedNodeDC(this); // To draw drag image
	CDC			*pDragImageCalcDC = NULL;	// to find the drag image width and height
	CString		strItemText;
	CBitmap		*pBitmapOldMemDCBitmap = NULL; // Pointer to bitmap in memory
	CFont		*pFontOld = NULL; // Used for  bitmap font
	int			nIdx = 0, nCounter = 0; // Counts array elements
	int			nMaxWidth = 0;		// holds the maximum width to be taken to form the bounding rect
	
	//UINT		uiSelectedItems;  // Holds an item
	CImageList	*pImageListDraggedNode = NULL; // Holds an image list pointer

	nNumSelected = m_vSelItem.size();
	if( nNumSelected > 0)
	{
		pDragImageCalcDC = GetDC();
		if(pDragImageCalcDC == NULL)
		{
			return NULL;
		}
		CImageList *pImageList = GetImageList(TVSIL_NORMAL);
		if (pImageList == NULL)
		{
			return NULL;
		}

		//HICON hIcon = pImageList->ExtractIcon(nImg);
		int cx,cy;
		ImageList_GetIconSize(*pImageList, &cx, &cy);

		// Calculate the maximum width of the bounding rectangle
		for ( nIdx = 0; nIdx < nNumSelected; nIdx++)
		{
			// Get the item's height and width one by one
			hItem = m_vSelItem[nIdx];
			strItemText = GetItemText(hItem);
			rectFirstItem.SetRectEmpty();
			pDragImageCalcDC->DrawText(strItemText, rectFirstItem, DT_CALCRECT);//得到rect
			if(nMaxWidth < ( rectFirstItem.Width()+cx))
			{
				nMaxWidth = rectFirstItem.Width()+cx;
			}
		}

		// Get the first item's height and width
		hItem = m_vSelItem[0];
		strItemText = GetItemText(hItem);
		rectFirstItem.SetRectEmpty();
		pDragImageCalcDC->DrawText(strItemText, rectFirstItem, DT_CALCRECT);
		ReleaseDC(pDragImageCalcDC);

		// Initialize textRect for the first item
		rectTextArea.SetRect(1, 1, nMaxWidth, rectFirstItem.Height());

		// Find the bounding rectangle of the bitmap
		rectBounding.SetRect(0,0, nMaxWidth+2, (rectFirstItem.Height()+2)*nNumSelected);

		CDC MemoryDC; // Memory Device Context used to draw the drag image
		// Create bitmap		
		if( !MemoryDC.CreateCompatibleDC(&DraggedNodeDC) )
		{
			return NULL;
		}
		CBitmap		DraggedNodeBmp; // Instance used for holding  dragged bitmap
		if( !DraggedNodeBmp.CreateCompatibleBitmap(&DraggedNodeDC, rectBounding.Width(), rectBounding.Height()) )
		{
			return NULL;
		}

		pBitmapOldMemDCBitmap = MemoryDC.SelectObject( &DraggedNodeBmp );
		pFontOld = MemoryDC.SelectObject(GetFont());

		CBrush brush(RGB(255,255,255));
		MemoryDC.FillRect(&rectBounding, &brush);
		MemoryDC.SetBkColor(RGB(255,255,255));
		MemoryDC.SetBkMode(TRANSPARENT);
		MemoryDC.SetTextColor(RGB(0,0,0));

		// Search through array list
		for( nIdx = 0; nIdx < nNumSelected; nIdx++)
		{
			hItem = m_vSelItem[nIdx];
			int nImg = 0,nSelImg=0;
			GetItemImage(hItem,nImg,nSelImg);
			HICON hIcon = pImageList->ExtractIcon(nImg);
			//cdcMemory.DrawIcon(rectTextArea.left,rectTextArea.top,hIcon);
			MemoryDC.MoveTo(rectTextArea.left,rectTextArea.top);
			if( nIdx != nNumSelected-1 )
			{
				MemoryDC.LineTo(rectTextArea.left,rectTextArea.top+18);
			}
			else
			{
				MemoryDC.LineTo(rectTextArea.left,rectTextArea.top+8);
			}
			MemoryDC.MoveTo(rectTextArea.left,rectTextArea.top+8);
			MemoryDC.LineTo(rectTextArea.left+5,rectTextArea.top+8);

			int nLeft = rectTextArea.left;
			rectTextArea.left += 3;

			::DrawIconEx(MemoryDC.m_hDC,rectTextArea.left,rectTextArea.top,hIcon,\
				16,16,0,NULL,DI_NORMAL);

			rectTextArea.left += cx;
			MemoryDC.Rectangle(rectTextArea);
			MemoryDC.DrawText(GetItemText(hItem), rectTextArea, DT_LEFT| DT_SINGLELINE|DT_NOPREFIX);
			rectTextArea.left = nLeft;
			rectTextArea.OffsetRect(0, rectFirstItem.Height()+2);
			DestroyIcon(hIcon);
		}
		MemoryDC.SelectObject( pFontOld );
		MemoryDC.SelectObject( pBitmapOldMemDCBitmap );
		MemoryDC.DeleteDC();
		// Create imagelist
		pImageListDraggedNode = new CImageList;
		pImageListDraggedNode->Create(rectBounding.Width(), rectBounding.Height(),\
			ILC_COLOR | ILC_MASK, 0, 1);

		pImageListDraggedNode->Add(&DraggedNodeBmp, RGB(255, 255,255)); 

		return pImageListDraggedNode;
	}
	return NULL;
}


最后是响应左键弹起:

void CDragDropTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if( !(MK_CONTROL&nFlags) && !(MK_SHIFT&nFlags) )
	{
		if( m_vSelItem.size() > 1 )
		{
			ClearSelection();
			SetItemState(m_hLastSelItem,TVIS_SELECTED,TVIS_SELECTED);
			m_vSelItem.push_back(m_hLastSelItem);
		}    
	}

	if ( m_bDragging && m_pImageList != NULL ) 
	{
		m_bDragging = FALSE;    
		//KillTimer(1);
		ReleaseCapture();
		//
		// Terminate the dragging operation and release the mouse.
		//
		m_pImageList->DragLeave (this);
		m_pImageList->DragLeave (GetParent());
		m_pImageList->EndDrag ();
		SelectDropTarget(NULL);
		delete m_pImageList;
		m_pImageList = NULL;
		HTREEITEM hItem = HitTest(point,&nFlags);//得到鼠标松开时落点的item
		int nListenerCount = m_vEventListener.size();
		for( int  nListenerIdx = 0; nListenerIdx < nListenerCount; ++nListenerIdx )
		{
			m_vEventListener[nListenerIdx]->OnDragRelease(point,hItem);//外部接口实现
		}
	}
	CTreeCtrl::OnLButtonUp(nFlags, point);
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值