Drag and drop
Posted
by Zafir Anjum
on August 6th, 1998
Step 0: Make sure that the control style supports drag and drop
If the control has the TVS_DISABLEDRAGDROP style then the TVN_BEGINDRAG notification is not sent. So make sure that the control does not have the TVS_DISABLEDRAGDROP style.Step 1: Declare member variables
Add member variables to the CTreeCtrl derived class to track whether drag and drop is in progress and the handle of the drag item and the drop location. The m_pDragImage variable holds the image list used during the drag and drop operation.protected: CImageList* m_pDragImage; BOOL m_bLDragging; HTREEITEM m_hitemDrag,m_hitemDrop;
Step 2: Add handler for TVN_BEGINDRAG
You can use the class wizard to add a handler for the TVN_BEGINDRAG notification. The handler function has been named OnBeginDrag() in the listing below. The code first sets up the member variables. It then creates an image that will drag across the screen as the mouse moves. CreateDragImage() is a member of the CTreeView class and it creates an image consisting of the item image and the label text.BeginDrag() function is called with an argument of zero and a point. The zero indicates the first image, which is the only image in the image list. The value we use for the second argument causes the image to be drawn to the right lower side of the cursor. You may want to experiment with this value if the image position does not suit your taste.
We call the DragEnter() to display the drag image. The first argument
is NULL so that the drag image will be visible even if the mouse is dragged
outside the treeview control.
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() returns NULL if no image list
// associated with the tree view control
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();
}
Step 3: Add handler for WM_MOUSEMOVE to update drag image
In this handler we basically update the position of the drag image and update the drop position. The DragMove() function moves the drag image. We then update the drop target if the mouse is over a tree view item. Note the calls to DragShowNolock(). The first call hides the drag image and allows the tree view control to be updated. The second calls displays the drag image again. We can also use a combination of DragLeave() and DragEnter() but I found that using these functions causes some redraw problems.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);
SelectDropTarget(hitem);
m_hitemDrop = hitem;
CImageList::DragShowNolock(TRUE);
}
}
CTreeCtrl::OnMouseMove(nFlags, point);
}
Step 4: Finally add handler for WM_LBUTTONUP
It is in the WM_LBUTTONUP handler that we complete the drag and drop process. We first determine whether a drag - drop operation was in progress. This is a good place to delete the image list object we created by calling CreateDragImage() in OnBeginDrag() function. Before moving the branch we make sure that the move is valid. The call to Expand() is normally not necessary, however, if we implement dynamic loading, wherein the items are loaded only after the parent is expanded then this call is important.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;
// Remove drop target highlighting
SelectDropTarget(NULL);
if( m_hitemDrag == m_hitemDrop )
return;
// If Drag item is an ancestor of Drop item then 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 );
}
}

Comments
no source code ?
Posted by suchuhui80 on 02/14/2006 11:00pmwhere can I download your whole project ? error C2065: 'SelectDropTarget' : undeclared identifier error C2065: 'GetParentItem' : undeclared identifier
Replyset mouse position
Posted by Legacy on 01/20/2004 12:00amOriginally posted by: astian
How to set the position of the mouse pointer on the screen in VC++
Replya little improvement.
Posted by Legacy on 06/30/2003 12:00amOriginally posted by: johnson yang
ReplyDrag Image problems
Posted by Legacy on 05/12/2003 12:00amOriginally posted by: Patrick Fitzpatrick
When I use this code, the image that is created for the drag contains the text of the tree item too. If I drag a different tree item, the text does not change and always gives me the text of the first dragged item. Any Idea how to solve this?
-
ReplyCreateDragImage(m_hitemDrag) problems
Posted by 81quang on 12/27/2005 03:55amThis method always returns NULL value I don't know why ? Please help me
ReplyI can't find MouseMove and MouseUp events
Posted by Legacy on 02/19/2003 12:00amOriginally posted by: Adriana
My program is a Dialog based app and I have included a Tree control, so I don't have a class for CTreeCtrl to create this events from. I was able to create a MouseMove and MouseUp functions but they are from my main dialog (CDialog) and it will work for a short time, then when draging the image will only show in the rest of my dialog except over the tree control.
Does anybody have an idea?. I will really appreciate it. Thanx =D
ReplySome usefull tips
Posted by Legacy on 10/25/2002 12:00amOriginally posted by: Anibal Itriago
Replysound work!!
Posted by Legacy on 09/28/2002 12:00amOriginally posted by: Ben
working great!
Replyminor update (delete m_pDragImage / etc patch included...)
Posted by Legacy on 08/07/2002 12:00amOriginally posted by: Seok Heon Seop[KOREA]
if m_pDragImage is NULL, "delete m_pDragImage" command is fatal error.
repair!!
included patch:
Avoiding flicker during drag'n drop
Minor change to the constructor
[constructor]
CTreeCtrlEx::CTreeCtrlEx()
{
.......
.......
m_pDragImage = NULL;
m_bLDragging = FALSE;
}
void CTreeCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
{
.......
.......
CImageList::DragMove(pt);
hitem = HitTest(point, &flags);
if (hitem != m_hitemDrop)
{
CImageList::DragShowNolock(FALSE);
SelectDropTarget(hitem);
m_hitemDrop = hitem;
CImageList::DragShowNolock(TRUE);
}
.......
.......
}
void CTreeCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
{
.......
.......
ReleaseCapture();
if(m_pDragImage != NULL)
{
delete m_pDragImage;
m_pDragImage = NULL;
}
.......
.......
}
^____________________^;;;;;;;
Reply
The OnBeginDrag () function is never been called?
Posted by Legacy on 06/03/2002 12:00amOriginally posted by: Mihir
HI all,
the onBeginDrag function never got called.. I think it can be because my tree view has a function called on LButtonDown. so is this the problem?>??????????
I dont know why it never reaches there?
thanks,
Replymihir.
Works great!
Posted by Legacy on 04/11/2002 12:00amOriginally posted by: Ron Wolfe
I really like the way this code works. I looked for over a week for 'how' to use dragdrop, but stumbled upon this and many thanks to the author. The only trouble I had was, being a newbie, I had a bit of trouble getting it to work, until I realized all I had to do was build a couple bitmap images for it to load. Thanks again.
ReplyLoading, Please Wait ...