Implementing a Drag Source






4.75/5 (4 votes)
Simple step by step article explaining how to implement a drag source
This article is part of the drag and drop interface samples.
- Serializing ASCII Data
- Modeless child dialog
- Modeless sibling dialog
- The drag source
- The MFC drop target
- The TBTextTarget class
Data is Going Abroad... Implementing the Drag Source
Again, the implementation of this idea is in two different versions.
Version one uses user-defined data and may better fit your needs.
As we are dealing here with a list control, it may be considerable to use a standard format instead with version two. As a side-effect, you can now drag the contents of your list control to Word, Excel, Visual Studio, or any other drop-enabled texteditor - do I see you smile?
Both versions are very similar. To implement both of them with my application, I made use of the registry settings. Use the menu items at "Clipboard format" or the HKEY_CURRENT_USER\Software\Codeguru\Interface\DragDrop\Clipformat string to specify either the default of "Common
" or the string "Private
". Any other value will cause an error message and the assumption of the Common type.
Follow these steps:
- To the view, add a member-variable of type
UINT
:UINT m_DragDropFormat;
- In the constructor of the view, initialize it for private data exchange with:
m_DragDropFormat = ::RegisterClipboardFormat("YourInterfaceClipboardFormat");
and for the common format, just use:
m_DragDorpFormat = CF_TEXT;
Do the same to your drop target. In our case, it’s either of the modal dialogs created in step one.
- Add the following lines to stdafx.h:
#include <afxdisp.h> #include <afxole.h>
In your application’s
InitInstance
function, make a call toAfxOleInit()
before creating the document template. #include <afxadv.h>
in your drag-source-class source file (or in stdafx.h, it's forCSharedFile
used in Step 5).- (Private data) Use the Class Wizard to add a message handler to your view, which responds to the
LVN_BEGINDRAG
message of the list control. Here is the functionOnBeginDragList1
for the private-data-version:void CInterfaceView::OnBeginDragList1(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; *pResult = 0; // Create the drag&drop source and data objects COleDropSource *pDropSource = new COleDropSource; COleDataSource *pDataSource = new COleDataSource; // now determine which rows are selected // copy from the CListCtrl section int idx = GetSelectedItem(); if (idx == -1 || !m_DragDropFormat) { // nothing selected (must be for dragging) // or error while registering the clipboard format ASSERT(FALSE); return; } // now grab the data (here: the count and text) // and serialize (hoho!) it into an clipboard archive CString Data; // getting the column count, thanks Zafir! CHeaderCtrl* pHeader = (CHeaderCtrl*)m_Table.GetDlgItem(0); int number = m_Table.GetSelectedCount(), colCou = pHeader?pHeader->GetItemCount():0; TRY { CSharedFile file(GMEM_ZEROINIT|GMEM_DDESHARE|GMEM_MOVEABLE); TRY { CArchive ar(&file, CArchive::store); TRY { // Write the number of items and columns ar << number; ar << colCou do { for (int i=0; i<colCou; i++) { Data = m_Table.GetItemText(idx, i); ar << Data ; } idx = GetSelectedItem(idx); } while (idx != -1); ar.Close(); } CATCH_ALL(eInner) { // exception while writing into or closing the archive ASSERT(FALSE); } END_CATCH_ALL; } CATCH_ALL(eMiddle) { // exception in the destructor of ar ASSERT(FALSE); } END_CATCH_ALL; // put the file object into the data object pDataSource->CacheGlobalData(m_DragDropFormat, file.Detach()); pDataSource->DoDragDrop(DROPEFFECT_MOVE|DROPEFFECT_COPY, NULL, pDropSource); } CATCH_ALL(eOuter) { // exception while destructing the file ASSERT(FALSE); } END_CATCH_ALL; delete pDropSource; delete pDataSource; }
Here is the function
OnBeginDragList1
for the common-data-version. It even allows you to drag your data to Excel! (common data)//... the same until CSharedFile file; TRY { CArchive ar(&file, CArchive::store); TRY { // for CF_TEXT use a flat ASCII-stream // using tabs as delimiter will cause Excel and others to // understand us that we have a table CString number; number.Format("%i\n", m_Table.GetSelectedCount()); ar.WriteString(number); do { Data.Empty(); for (int i=0; i<colCou; i++) Data += m_Table.GetItemText(idx, i) + "\t"; ar.WriteString(Data + "\n"); idx = GetSelectedItem(idx); } while (idx != -1); ar.Close(); } CATCH_ALL(eInner) // and do the rest as above ...