"Операция при которой пользователь используем мышь или другое указывающее устройство для перемещения данных из одного окна в другое". Именно так звучит определение Drag'n'Drop в MSDN. В данном примере мы рассмотрим метод именно _перемещения_ данных пользователем. Все делается в 5 шагов:
Шаг 1: Убедитесь, что Ваше дерево поддерживает drag'n'drop Флаг TVS_DISABLEDRAGDROP должен быть отключен. Иначе сообщение TVN_BEGINDRAG не будет послано.
Шаг 2: Объявите переменные-члены protected: CImageList*m_pDragImage;//содержит список изображений используемый во время переноса BOOLm_bLDragging; HTREEITEMm_hitemDrag,m_hitemDrop;
Шаг 3: Добавьте обработчик для TVN_BEGINDRAG Функция BeginDrag() вызывается с аргументами 0 и координатами точки. Ноль обозначает номер изображения в списке, точка - координаты относительно курсора этого изображения. Затем мы вызываем DragEnter(), чтобы показать изображение. Первый параметр NULL - для того, чтобы изображение было видно за пределами дерева. void CTreeCtrlX::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; *pResult = 0;
m_hitemDrag = pNMTreeView->itemNew.hItem; m_hitemDrop = NULL;
m_pDragImage = CreateDragImage(m_hitemDrag); // get the image list for dragging // 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(); }
Шаг 4: Добавьте обработчик для WM_MOUSEMOVE - обновление перетаскивамого изображения В этом обработчике мы обновляем позицию взятого изображения и цель бросания. Функция DragMove() перемещает изображение. Затем мы должны обновить цель, если мышь появляется над деревом. Делаем это с помощью двух вызовов функции DragShowNolock(). Первый: скрывает изображение и позволяет обновить информацию, второй: показывает изображение снова. Можно было бы использовать DragLeave() / DragEnter(), но тут иногда возникают проблемы перерисовки. void CTreeCtrlX::OnMouseMove(UINT nFlags, CPoint point) { HTREEITEMhitem; UINTflags;
if (m_bLDragging) { POINT pt = point; ClientToScreen( &pt ); CImageList::DragMove(pt); if ((hitem = HitTest(point, &flags)) != NULL) { CImageList::DragShowNolock(FALSE); SelectDropTarget(hitem); m_hitemDrop = hitem; CImageList::DragShowNolock(TRUE); } }
CTreeCtrl::OnMouseMove(nFlags, point); }
Шаг 5: Наконец добавьте обработчик для WM_LBUTTONUP В обработчике WM_LBUTTONUP мы завершаем drag'n'drop процесс. Сначала мы определяем, что находимся в режиме drag'n'grop. Это хорошее место для того, чтобы удалить список изображений созданный функцией CreateDragImage() в методе OnBeginDrag(). Перед перемещением убедимся, что все действия кооректны. В вызове Expand(), в принципе, нет необходимости, но если мы объявили динамическую загрузку, где элементы загружаются, когда ветвь раскрывается, он необходим. 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 ) 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 ); }
}
|