CTreeCtrl 中的 MultiSelect DragImage






4.16/5 (16投票s)
本文档描述了如何在 CTreeCtrl 中创建多选拖拽图像。
引言
本文档描述了如何在 CTreeCtrl
中创建多选拖拽图像。我创建了一个自定义树控件 CDragDropTreeCtrl
(从 CTreeCtrl
派生)来添加拖放支持。CreateDragImageEx()
是核心函数,它创建拖拽图像列表。
CDragDropTreeCtrl
此类实现了使用鼠标,并按下 Ctrl 或 Shift 键进行多选。使用 DragDetect()
API 检测拖拽的开始。一旦检测到拖拽,就会调用 OnDrag()
函数。OnDrag()
函数调用 CreateImageEx()
来创建拖拽图像列表。其余部分与单选拖拽相同。使用 BeginDrag()
和 DragEnter()
函数为拖拽准备图像列表。在鼠标移动事件中,拖拽图像会被移动。
CreateDragImageEx
这是核心函数,用于创建拖拽图像列表。创建拖拽图像列表的步骤如下:
- 获取与树控件关联的图像列表
- 使用 API
ImageList_GetIconSize()
获取图标大小 - 计算拖拽图像的边界矩形
- 计算最大宽度
- 计算单个项目的高度,并将其乘以列表大小以获得总高度
- 创建一个内存设备上下文
- 准备内存 DC
- 创建并准备位图对象
- 将位图选择到内存 DC 中
- 对于列表中的每个元素,提取图标和关联的文本,并将它们绘制到内存 DC 中
- 创建一个新的图像列表
- 将位图添加到图像列表中
// 1.Get the image list associated with the tree control
CImageList *pImageList = GetImageList(TVSIL_NORMAL);
// 2.Get the icon size with the help of the API ImageList_GetIconSize()
int cx,cy;
ImageList_GetIconSize(*pImageList, &cx, &cy);
// 3.Calculate the bounding rect of the drag image
// a) Calculate the maximum width
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);
if(nMaxWidth < ( rectFirstItem.Width()+cx))
nMaxWidth = rectFirstItem.Width()+cx;
}
// b) Calculate the height of single item and multiply it
// with list size to get the total height
hItem = m_vSelItem[0];
strItemText = GetItemText(hItem);
rectFirstItem.SetRectEmpty();
pDragImageCalcDC->DrawText(strItemText, rectFirstItem, DT_CALCRECT);
rectTextArea.SetRect(1, 1, nMaxWidth, rectFirstItem.Height());
rectBounding.SetRect(0,0, nMaxWidth+2,
(rectFirstItem.Height()+2)*nNumSelected);
// 4.Create a memory device context
CDC MemoryDC;
// 5.Prepare the memory DC
if(!MemoryDC.CreateCompatibleDC(&DraggedNodeDC))
return NULL;
// 6.Create and prepare bitmap object
CBitmap DraggedNodeBmp;
if(!DraggedNodeBmp.CreateCompatibleBitmap(&DraggedNodeDC,
rectBounding.Width(), rectBounding.Height()))
return NULL;
// 7.Select Bitmap into the memory DC
pBitmapOldMemDCBitmap = MemoryDC.SelectObject( &DraggedNodeBmp );
// 8.For each element in the list extract the icon
// and associated text and draw them to the memory DC
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);
}
// 9.Create a new image list
pImageListDraggedNode = new CImageList;
pImageListDraggedNode->Create(rectBounding.Width(), rectBounding.Height(),
ILC_COLOR | ILC_MASK, 0, 1);
// 10.Add the bitmap to the image list
pImageListDraggedNode->Add(&DraggedNodeBmp, RGB(255, 255,255));
结论
此 CDragDropTreeCtrl
仅实现使用鼠标进行多选。键盘支持将在以后更新。使用这种方法创建拖拽图像列表,我们也可以为列表控件创建拖拽图像。