控件“树”中多选拖放功能的实现
2007-03-30 21:32:29 来源:WEB开发网核心提示: 图1:拖放操作过程中显示的拖放图象开始拖动(Beginning a drag)拖动操作开始时,"树"控件的父窗口将接收到一个通知消息TVN_BEGINDRAG,控件“树”中多选拖放功能的实现(3),您可以向CBitmapTree类的消息映象中发送一通知消息ON_NOTI
图1:拖放操作过程中显示的拖放图象
开始拖动(Beginning a drag)拖动操作开始时,"树"控件的父窗口将接收到一个通知消息TVN_BEGINDRAG。您可以向CBitmapTree类的消息映象中发送一通知消息ON_NOTIFY_REFLECT_EX,以此来截获通知消息TVN_BEGINDRAG,并将其同时发送给父窗口和"树"控件,下面就是TVN_BEGINDRAG的消息处理函数:
BOOL CBitmapTree::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
HTREEITEM h= pNMTreeView->itemNew.hItem;
int img, simg;
CPoint point;
if ((m_dragFunction == NULL) || (h == NULL))
return(FALSE);
ASSERT(GetNormalImageCount());
if (m_multiSelected)
{
// 关闭不可拖动项的选择操作
DoForAllSelected(PrepareDrag, NULL, 0);
}
else
{
// 如果已经开始拖动一个"非选择项",
// 则需要在拖动前改变该项的拖动特性
SelectItem(h);
}
// 能拖动此项吗?
GetItemImage(h, img, simg);
if (!(IsDraggable(h, img)))
return(FALSE);
// 设置拖动图象列表
if (m_ilDrag.m_hImageList != NULL)
m_dragList= &m_ilDrag;
else
{
m_dragList= CreateDragImage(h);
if (m_dragList == NULL)
return(FALSE);
}
if (m_multiSelected)
m_dragList->BeginDrag(m_multiDrag, CPoint(0,0));
else
m_dragList->BeginDrag(m_docDrag, CPoint(0,0));
MapWindowPoints(NULL, &pNMTreeView->ptDrag, 1);
m_dragList->DragEnter(NULL, pNMTreeView->ptDrag);
ShowCursor(FALSE);
SetCapture();
// 允许边拖动边滚动"树"控件窗口
SetTimer(EVENT_DRAG_SCROLL, 250, NULL);
*pResult= 0;
return(FALSE);
}
当调用OnBeginDrag()函数时,首先判断是否为多节点拖动,当m_multiSelected值为真,即为多节点拖动时,将调用PrepareDrag()函数来关闭那些未声明为"可拖动"项的选择操作(负责调用函数PrepareDrag()的函数DoForAllSelected()在文章〖1〗中有所描述)。然后再调用函数IsDraggable()检验一下当前所选的项是否都是可拖动项,如果有不可拖动项,则函数返回FALSE,否则,继续下面的语句,初始化拖动操作过程中显示的图象列表,调用函数BeginDrag()。MSDN文档中解释说函数BeginDrag()中的第二个参量为"起始拖动位置的坐标(典型情况下为光标位置)"。文档中建议第二个参量使用光标的当前位置坐标,并且将其存储在pNMTreeView->ptDrag中,事实上,这也正是程序示例MFCTREE中所采用的方法。但是,最近的MSDN应用程序示例CMNCTRLS和TREESCR中使用的是(0,0),上面的代码段中也使用(0,0)。OnBeginDrag()函数的后一部分调用了函数DragEnter()来初始化拖动操作。在调用完函数DragEnter()以后,如果想刷新控件"树",那么就需要首先调用DragLeave()函数。
更多精彩
赞助商链接