Расширенный drag'n'drop
В этом примере добавлено три новых возможности.
Теперь по желанию можно делать не активными
заданные элементы для drag'n'drop. Вы так же можете
решать является ли элемент доступным для
бросания, если нет, то предоставляется
альтернативный элемент этого. Курсор отражает
все состояния операции drag'n'drop.
Члены-переменные, которые должны быть объявлены:
protected:
CImageList* m_pDragImage;
BOOL m_bLDragging;
HTREEITEM m_hitemDrag,m_hitemDrop;
HCURSOR m_dropCursor,m_noDropCursor;
m_dropCursor и m_noDropCursor инициализированы в
соответствии с желаемым видом курсоров
Авторская версия OnBeginDrag(...):
void CTreeCtrlX::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
*pResult = 0;
m_hitemDrag = pNMTreeView->itemNew.hItem;
m_hitemDrop = NULL;
SelectItem( m_hitemDrag );
if (!IsDropSource(m_hitemDrag))
return;
// Взять список изображений для перетаскивания
m_pDragImage = CreateDragImage(m_hitemDrag);
// CreateDragImage() возвращает NULL если никакого списка
// изображений не было связано с деревом
if( !m_pDragImage )
return;
m_bLDragging = TRUE;
m_pDragImage->BeginDrag(0, CPoint(15, 15));
POINT pt = pNMTreeView->ptDrag;
ClientToScreen( &pt );
m_pDragImage->DragEnter(NULL, pt);
SetCapture();
}
Этот метод вызывает IsDropSource(), чтобы
определить возможность drag'n'drop операции для
заданного элемента. Если IsDropSource() возвращает FALSE,
то перетаскивание запрещено. По умолчанию IsDropSource()
всегда возвращает TRUE.
Авторская версия обработчика OnMouseMove():
void CTreeCtrlX::OnMouseMove(UINT nFlags, CPoint point)
{
HTREEITEM hitem;
UINT flags;
if (m_bLDragging)
{
POINT pt = point;
ClientToScreen( &pt );
CImageList::DragMove(pt);
if ((hitem = HitTest(point, &flags)) != NULL)
{
CImageList::DragShowNolock(FALSE);
m_hitemDrop = GetDropTarget(hitem);
SelectDropTarget(m_hitemDrop);
CImageList::DragShowNolock(TRUE);
}
else
m_hitemDrop = NULL;
if (m_hitemDrop)
SetCursor(m_dropCursor);
else
SetCursor(m_noDropCursor);
}
CTreeCtrl::OnMouseMove(nFlags, point);
}
Вызов этой версии GetDropTarget() решает
лигитимность цели бросания, находящейся под
курсором. Она возвращает NULL, если элемент не
может принять бросок; HTREEITEM, если может. Как
альтернатива HTREEITEM может быть возвращено,
определяя разные цели бросания. Это может быть
полезно, например, если не Вы не принимаете
элемент на "листья" дерева, но хотите
направить его в корень.
/* virtual */ HTREEITEM CTreeCtrlX::GetDropTarget(HTREEITEM hItem)
{
if (hItem == m_hitemDrag || hItem == GetParentItem(m_hitemDrag))
return NULL;
return hItem;
}
И наконец обработчик OnLButtonUp():
void CTreeCtrlX::OnLButtonUp(UINT nFlags, CPoint point)
{
CTreeCtrl::OnLButtonUp(nFlags, point);
if (m_bLDragging)
{
m_bLDragging = FALSE;
CImageList::DragLeave(this);
CImageList::EndDrag();
ReleaseCapture();
delete m_pDragImage;
// Удаляем подсветку цели
SelectDropTarget(NULL);
if( m_hitemDrag == m_hitemDrop || m_hitemDrop == NULL)
return;
HTREEITEM htiParent = m_hitemDrop;
while( (htiParent = GetParentItem( htiParent )) != NULL )
{
if( htiParent == m_hitemDrag ) return;
}
Expand( m_hitemDrop, TVE_EXPAND ) ;
HTREEITEM htiNew = CopyBranch(m_hitemDrag, m_hitemDrop, TVI_LAST );
DeleteItem(m_hitemDrag);
SelectItem( htiNew );
}
}
Источник: ProtoSphere
|