Click here to Skip to main content
15,887,975 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
INTRODUCTION:

I am implementing rearranging of listview items without using OLE drag and drop.

PROBLEM:

I have successfully solved most of this task, except scrolling up/down when user wants to drop items at the position that is not currently visible.

QUESTION:

I am able to scroll up/down listview by using following messages:

C++
SendMessage(hwndListView, WM_VSCROLL, (WPARAM)SB_LINEUP, (LPARAM)0);
SendMessage(hwndListView, WM_VSCROLL, (WPARAM)SB_LINEDOWN, (LPARAM)0);

I need your advice in figuring out when and where I need to send those messages ( I suppose it should be done on WM_MOUSEHOVER or something like that? ).

I just do not know on which message, and how, I should check if scrolling is needed.

I am interested in implementing default scrolling behavior for drag and drop.

MY EFFORTS TO SOLVE THIS:

I have tried to use listview hit testing so I can examine LVHITTESTINFO[^] for LVHT_ABOVE and LVHT_BELOW but that did not work for me.

I was never able to get those values when clicking on listview...

I have found some examples in other programming languages that use timers to implement this. I am studying them as I write this post.

ADDITIONAL INFO:

Listview is in report mode and supports multiselection.

I am handling following messages:

C++
LVN_BEGINDRAG  // I create drag image here
WM_MOUSEMOVE   // I update drag image here
WM_LBUTTONUP   // I rearrange items here and perform cleanup

I have omitted SSCCE to keep this post short. If needed I can post it. If further info is required please leave a comment.
Posted
Updated 2-Mar-15 21:55pm
v2
Comments
Jochen Arndt 3-Mar-15 3:33am    
If you are interested I can help you with using OLE. CView derived classes are prepared for drag & drop support including scrolling.

If not, you should use WM_MOUSEMOVE and check if over a scrolling area. Scrolling areas are the scroll bars and commonly an inset region (a small band inside the borders of the client area). Then scroll up/down according to the y position (above / below center). For an example see the MFC COleDropTarget::OnDragScroll source.
AlwaysLearningNewStuff 3-Mar-15 3:43am    
If you are interested I can help you with using OLE. I am actually studying OLE on my own, so yes, I am interested. I have read Raymond Chen's blogs on the topic, so this may help us "speed up" the process.

CView derived classes are prepared for drag & drop support including scrolling. I do not know MFC, if that is what you refer to. If you refer to a class that implements OLE interfaces I will gladly give it a try.
Jochen Arndt 3-Mar-15 5:11am    
CView is MFC (all MS classes beginning with upper letter C are MFC). The sources are installed with Visual Studio (VCx\atlmfc\src).

I have started writing an article about drag & drop with drag images and new cursors two years ago. But I'm still not happy with it and the demo / sources need some more work. I will post a short extraction as answer.

Jochen Arndt 16-Mar-15 5:20am    
Your questions inspired me to finalise my article. You may have a look at it: http://www.codeproject.com/Articles/886711/Drag-drop-images-and-drop-descriptions-for-MFC-app
AlwaysLearningNewStuff 17-Mar-15 16:38pm    
When I try your demo app it hangs... I have tested it on Windows 7 x86, if this info matters... Article seems awesome, but I can not make your demo app work on my laptop...

1 solution

CView derived classes are prepared for drag & drop.

To register a window as a drop target, add a COleDropTarget member to your class and call the Register() function passing the CWnd pointer to the window. The common place to do this is OnInitialUpdate() with view windows:
C++
void CMyListView::OnInitialUpdate(void)
{
    // m_pDropTarget is a CView member that will be set upon registering
    if (NULL == m_pDropTarget)
        m_DropTarget.Register(this);
}

You can now implement your versions of the virtual drag functions:

OnDragEnter

This is called when dragging the first time (or again after leaving) over the window. At first it should be checked if the window is able to drop data (window is enabled and an optional read only state is not set). Then check if the drag source provides data that can be dropped. Additional checks may be if the provided data would fit (e.g. number of text characters is less than a specified limit). The result of these checks may be stored in a member variable to be used by OnDragOver(). The returned drop effect should be determined like the one returned by OnDragOver().

OnDragOver

The main purpose is to set the drop effect according to the key state (e.g. copying when the Ctrl key is down and moving otherwise), and to check if data can be dropped on the current position (e.g. over the client area and not over a scroll bar or the header of a list control). This is called repeatedly when moving around the window (like the WM_MOUSEMOVE message) and when the key state (Shift, Ctrl, Alt) changes. So don't perform time consuming tasks inside this function. This is also called before OnDropEx() and OnDrop() to get the drop effect to be passed to these functions. Because the returned drop effect is used to determine the type of cursor and returned to the source upon dropping, it should be a single effect and not a combination of multiple effects.

OnDragLeave

This is called when leaving the window. Use it for cleanup. With most windows there is no need to implement this handler. If it is present to perform some cleanup, it may be necessary to add similar code to the drop handlers because OnDragLeave() is not called when a dropping occurs.

OnDrop and OnDropEx

Only one of these functions must be implemented. They are called when releasing the mouse button when over the window. Get the data here and insert them into the control when dropping should occur. When the mouse button is released, these functions are called:

  • OnDragOver() is called to get the drop effect to be passed to OnDropEx() and/or OnDrop().
  • OnDropEx() is called (even when the drop effect is DROPEFFECT_NONE).
  • When OnDropEx() returns -1 and the drop effect is not DROPEFFECT_NONE, OnDrop() is called.
  • When OnDropEx() returns -1 and the drop effect is DROPEFFECT_NONE, OnDragLeave() is called.

Because OnDropEx() is always called even when the drop effect is DROPEFFECT_NONE, OnDropEx() should check the passed value and return without dropping in this case.

OnDragScroll

This can be handled to perform auto scrolling when dragging over a scrollbar or an inset region (a small band inside the borders of the client area). OnDragScroll() is the first handler called when entering or moving over a window. When scrolling is active, the DROPEFFECT_SCROLL bit is set in the return value to avoid further processing. If the scroll bit is not set, OnDragEnter() resp. OnDragOver() is called.

Study the MFC COleDropTarget::OnDragScroll source to see how it is basically implemented.
 
Share this answer
 
Comments
AlwaysLearningNewStuff 7-Mar-15 5:05am    
Study the MFC COleDropTarget::OnDragScroll source to see how it is basically implemented. I was not able to find it. All I found was MSDN documentation for it. It is virtual function, as you have said, so no example was available there...
Jochen Arndt 7-Mar-15 5:15am    
It is on your hard disk (adjust path for your VS version):
\Program Files (x86)\Microsoft Visual Studio 12.0\VC\atlmfc\src\mfc\oledrop2.cpp

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900