Scrolling during drag and drop
In the implementation discussed below, we use a timer to enable us to drag the outline. We also scroll at varying speed depending on how far the cursor is from the border of the control.
Step 1: Add member variables to class
We declare two variables. One to hold the timer id and the other to hold a counter for the timer ticks. You may also choose to declare two more variable - for the event id that will be generated by the timer and the timeout value used for the timer. I have used hard coded values of 1 and 75 respectively.protected: UINT m_nTimerID; UINT m_timerticks;
Step 2: Set timer in TVN_BEGINDRAG handler
We install the timer in the TVN_BEGINDRAG handler. Place the following statement at the end of you handler function ( I have used OnBeginDrag() ) in previous sections.// Set up the timer m_nTimerID = SetTimer(1, 75, NULL);
Step 3: Add a WM_TIMER handler
You can use the class wizard to add the WM_TIMER handler. By default this function is given the name OnTimer(). We first make sure that we are handling the right timer event. The next task is to update the drag image position.We then determine whether scrolling is required. The criteria we use for this is that the cursor should be close to the top edge of the control or above the control. On the other end, if the cursor is near the bottom edge of the control or below the control, then we scroll in the other direction. We then compute a number to control the speed of scrolling. We have used a hard coded value of six different speed which should be enough. Each scroll speed range is 20 pixels tall. Ill leave the rest of the logic to control the scroll speed as an exercise for the reader - you.
You may notice that the call to DragMove() uses screen coordinates. The DragMove() function needs the screen coordinates if the call to DragEnter() when you began the drag operation had associtated the drag image to the desktop window. Use the client coordinates if the call to DragEnter() had specified the treeview control.
Before we go on the next step, Id like to discuss the behaviour of
GetVisibleCount(). This function is supposed to return the number of visible
items but instead it returns the maximum number of items that can be visible
at one time. We therefore make a check for NULL before calling SelectDropTarget().
void CTreeCtrlX::OnTimer(UINT nIDEvent)
{
if( nIDEvent != m_nTimerID )
{
CTreeCtrl::OnTimer(nIDEvent);
return;
}
// Doesn't matter that we didn't initialize m_timerticks
m_timerticks++;
POINT pt;
GetCursorPos( &pt );
RECT rect;
GetClientRect( &rect );
ClientToScreen( &rect );
// NOTE: Screen coordinate is being used because the call
// to DragEnter had used the Desktop window.
CImageList::DragMove(pt);
HTREEITEM hitem = GetFirstVisibleItem();
if( pt.y < rect.top + 10 )
{
// We need to scroll up
// Scroll slowly if cursor near the treeview control
int slowscroll = 6 - (rect.top + 10 - pt.y) / 20;
if( 0 == ( m_timerticks % (slowscroll > 0? slowscroll : 1) ) )
{
CImageList::DragShowNolock(FALSE);
SendMessage( WM_VSCROLL, SB_LINEUP);
SelectDropTarget(hitem);
m_hitemDrop = hitem;
CImageList::DragShowNolock(TRUE);
}
}
else if( pt.y > rect.bottom - 10 )
{
// We need to scroll down
// Scroll slowly if cursor near the treeview control
int slowscroll = 6 - (pt.y - rect.bottom + 10 ) / 20;
if( 0 == ( m_timerticks % (slowscroll > 0? slowscroll : 1) ) )
{
CImageList::DragShowNolock(FALSE);
SendMessage( WM_VSCROLL, SB_LINEDOWN);
int nCount = GetVisibleCount();
for ( int i=0; i<nCount-1; ++i )
hitem = GetNextVisibleItem(hitem);
if( hitem )
SelectDropTarget(hitem);
m_hitemDrop = hitem;
CImageList::DragShowNolock(TRUE);
}
}
}

Comments
nearly correct but found a small error
Posted by Legacy on 04/24/2002 12:00amOriginally posted by: Laz
The scroll works great but the dragged image appears to be way offline heres a 3 line fix to get that working aswell with your code around it so everyone can see where it should be included:-
if( nIDEvent != m_nTimerID )
{
//CTreeCtrl::OnTimer(nIDEvent);
CDTLUIXTreeViewEx::OnTimer(nIDEvent);
return;
}
// Doesn't matter that we didn't initialize m_timerticks
m_timerticks++;
POINT pt;
GetCursorPos( &pt );
RECT rect;
GetClientRect( &rect );
ClientToScreen( &rect );
// NOTE: Screen coordinate is being used because the call
// to DragEnter had used the Desktop window.
////////fix I added
// Basically you need to convert the point co-ordinates to
// screen ones to line up the dragged image properly,
// note I used a copy so that I don't have to edit
// your scroll code.
POINT pttemp = POINT(pt);
ClientToScreen( &pttemp );
CImageList::DragMove(pttemp);
/////// end of fix
HTREEITEM hitem = GetTreeCtrl().GetFirstVisibleItem();
if( pt.y < rect.top + 10 )
.
.
.
ReplyAnother Look at scroll during Drag and Drop
Posted by Legacy on 05/10/2001 12:00amOriginally posted by: Srinivasan Seetharaman
Replythe item dragged is blinking
Posted by Legacy on 03/16/2001 12:00amOriginally posted by: Oliv'
When you move an item, the call of CImageList::DragMove in OnTimer make the item blink.
When You stop it on tree, the item disapper
So it's better to declare a member POINT pt , updating it with a DragMove(pt) call in OnMouseMove, instead of updating it in the OnTimer event.
ReplySome improvements
Posted by Legacy on 11/15/1999 12:00amOriginally posted by: Geert Delmeiren
ReplyActiveX Control
Posted by Legacy on 08/04/1999 12:00amOriginally posted by: Tim
Where do I get the ActiveX control to be able to view treeview control on my web pages? Any info would be great.
Reply