15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Drag/drop from one tree control to another?

Matthias Bohlen -- MATTES@logotec.com
Monday, August 19, 1996

Environment: VC++ 4.0, NT 3.51

Hello,

in the sample project CMNCTRLS, I have seen how to program drag and drop
inside a CTreeCtrl. That was ugly. To make my life even more complicated,
I'd like to know how to drag'n'drop from a CTreeCtrl into something else,
maybe another CTreeCtrl, maybe an edit control, maybe even another
application (OLE?). 

Does anyone know how to do it?

Matthias
o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o

The ZEN master: "If you have a stick, I'll give you a
stick. If you have not, I'll take that stick away from
you".

The banker: "If you have money, I'll give you money.
If you have not, I'll take that money away from you".

----------------------------+--------------------------
Matthias Bohlen             |  Logotec Software GmbH
Phone: +49 228 64 80 520    |  Chateauneufstr. 10 
FAX:   +49 228 64 80 525    |  D-53347 Alfter, Germany
                            |  http://www.logotec.com/
E-mail: mattes@logotec.com  |  CAD systems development
----------------------------+--------------------------



Dave Frederick -- sasdrf@unx.sas.com
Tuesday, August 20, 1996

[Mini-digest: 6 responses]

> From: Matthias Bohlen 
> To: mfc-l@netcom.com
> Subject: Drag/drop from one tree control to another?
> Date: Monday, August 19, 1996 4:58 AM
> 
> Environment: VC++ 4.0, NT 3.51
> 
> Hello,
> 
> in the sample project CMNCTRLS, I have seen how to program drag and drop
> inside a CTreeCtrl. That was ugly. To make my life even more complicated,
> I'd like to know how to drag'n'drop from a CTreeCtrl into something else,
> maybe another CTreeCtrl, maybe an edit control, maybe even another
> application (OLE?). 
> 
> Does anyone know how to do it?
> 
> Matthias

There's a sample of OLE drag and drop using the common controls
(CListCtrl, but it should be easy to extrapolate to CTreeCtrl) on the 
MS Web Site. Look in the knowledge base for  Q152092 to find the
sample code. Good Luck!

--
Dave Frederick                SAS Institute, Inc.
Sr. Systems Developer     SAS Campus Drive
Compilers and Tools Div.  Cary, NC 27513
sasdrf@unx.sas.com        (919) 677-8000 x7049
-----From: "(Bobby)Babak Lashkari" 

I drag and drop from a CTreeView derived class into a CView derived
I don't know if it will work for CTreeCtrl or not
this is how I do it. Hope it'll help

void COldTreeView::OnTreeBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
{
  *pResult = 0;
  NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  
  SetCapture();
  if(this == CWnd::GetCapture())
    m_draging = TRUE;
  
  ::SetCursor(DragWndCursor);
}

void COldTreeView::OnMouseMove(UINT nFlags, CPoint point) 
{
  if(m_draging)
  {
    ClientToScreen(&point);
    CWnd* pWnd = WindowFromPoint( point );
    if(pWnd == this) 
      ::SetCursor(DragWndCursor);
    else if(pWnd->IsKindOf( RUNTIME_CLASS( COldView ) ) )
      ::SetCursor(DropOkCursor);
    else
      ::SetCursor(DropNotOkCursor);
  }      
  CTreeView::OnMouseMove(nFlags, point);
}


void COldTreeView::OnLButtonUp(UINT nFlags, CPoint point) 
{ 
  if(m_draging)
  {
    m_draging = FALSE;
    if(this != CWnd::GetCapture())
      return;
    ReleaseCapture();
    
    ClientToScreen(&point);
    CWnd* pWnd = WindowFromPoint( point );
    if(pWnd->IsKindOf( RUNTIME_CLASS( COldView ) ) )
    {
      GetDocument()->DoDropAction(pWnd);
    }
  }
	
  CTreeView::OnLButtonUp(nFlags, point);
}

-----From: pmoss@bbn.com (Peter Moss)

I have solved this problem for my application in which I want to drag an
item from a CTreeCtrl-derived object embedded in a CControlBar object
like the MSVC InfoViewer control bar.

The trick was that the notification msg for the start of the begin drag
operation (TVN_BEGINDRAG) is sent to the parent of the CTreeCtrl window,
not the CTreeCtrl itself. In the parent window, I handle the following
3 msgs:

TVN_BEGINDRAG notification
WM_MOUSEMOVE
WM_LBUTTONUP

The steps are as follows:

1) In the TVN_BEGINDRAG handler (you can use Class Wizard to write the
stub):
 o I change the cursor using SetCursor() to indicate a drag
  operation. 
 o In my app, I know the window where I will allow a
  drop operation. I get the coords of the client window of this
  drop target, and store them in a member variable in Screen
  coords (m_RectDropTarget).
 o I capture the mouse using SetCapture()

2) In OnMouseMove(), I change the shape of the cursor depending on the
window that the mouse is over. It becomes the NoDrop cursor if the
mouse is not over the Drop Target Window or the client window of the
CTreeCtrl.

3) In the OnLButtonUp() handler, I make sure the drop point is within
the window of my Drop Target. If not, I do nothing.

Here is some sample code from my app..

-----------------------------------------------

void CVarListBar::OnBegindragVarList(NMHDR* pNMHDR, LRESULT* pResult) 
{
 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
 // TODO: Add your control notification handler code here
 *pResult = 0;

 if (!m_pVarPropSheet)  // No prop sheet up, so return
  return;

 // Item to be dragged
 HTREEITEM hTItem = pNMTreeView->itemNew.hItem;
 
 if (GetItemType(hTItem) != VL_VARIABLE)  // Not a var
  return;
 
 CTreeCtrl* pVarListCtrl = (CTreeCtrl*)GetDlgItem(IDC_VARLIST);

 pVarListCtrl->SelectItem(hTItem);

 // Begin the drag

 // Change the cursor
 SetCursor(AfxGetApp()->LoadCursor(IDC_POINTER_COPY));
 m_etCursor = CT_COPY;

 // Determine drop rects
 pVarListCtrl->GetClientRect(&m_RectClient);  // Client rect
 pVarListCtrl->ClientToScreen(&m_RectClient); // Convert to screen coords

 m_pVarPropSheet->GetDropRect(&m_RectDropTarget);

 SetCapture();    // Capture the mouse

 TRACE0("CVarListBar::OnBegindragVarList\n");
}


void CVarListBar::OnMouseMove(UINT nFlags, CPoint point) 
{
 // TODO: Add your message handler code here and/or call default
 if (m_etCursor != CT_NORMAL) {
  // We are dragging an image
  CPoint ptScreen = point;
  ClientToScreen(&ptScreen);
  if (m_RectClient.PtInRect(ptScreen) || m_RectDropTarget.PtInRect(ptScreen)) {
   // Make it a Copy Cursor
   if (m_etCursor  != CT_COPY) {
    // Change the cursor
    ::SetCursor(AfxGetApp()->LoadCursor(IDC_POINTER_COPY));
    m_etCursor = CT_COPY;
   }
  }
  else {
   // Make it a Nodrop Cursor
   if (m_etCursor != CT_NODROP) {
    // Change the cursor
    ::SetCursor(AfxGetApp()->LoadCursor(IDC_NODROP));
    m_etCursor = CT_NODROP;
   }
  }
 }

 CSNDialogBar::OnMouseMove(nFlags, point);
}


void CVarListBar::OnLButtonUp(UINT nFlags, CPoint point) 
{
 // TODO: Add your message handler code here and/or call default
 if (m_etCursor != CT_NORMAL) {
  // I am dragging an item, but end it now

  SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));

  TRACE0("CVarListBar::OnLButtonUp Dragging finished\n");
  
  // Test to see if we dropped in the target rect
  CPoint ptScreen = point;
  ClientToScreen(&ptScreen);
  if (m_RectDropTarget.PtInRect(ptScreen)) {
   // User dropped in target area, so add the selected var
   CString VarName;
   LPARAM lParam;
   if (GetSelectedVar(VarName, lParam))
    m_pVarPropSheet->AddVar(VarName, lParam, &ptScreen);
  }
  
  ReleaseCapture();
  m_etCursor = CT_NORMAL;
 }

 CSNDialogBar::OnLButtonUp(nFlags, point);
}

Good Luck,
Pete Moss
pmoss@bbn.com

-----From: "Yury Kosov" 

	Hi Matthias,
	This is the way I'm doing this:
	In response to TVN_BEGINDRAG in the TreeControl parent:

MyClass::DoDrag(NMHDR *pns, LRESULT *result)
{
	COleDataSource dataSrc;

	HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,sizeof(MyData));
	MyData *cd = (ClipData *)GlobalLock(hMem);
	// stuff the memory with my data
	GlobalUnlock(hMem);
	dataSrc.CacheGlobalData(cf,hMem);

	CDropSource dropSrc;
	DROPEFFECT de = dataSrc.DoDragDrop(DROPEFFECT_COPY,0,&dropSrc);
	dataSrc.Empty();
	*result = 0;
}

	On the other side (usually in the View of some sort) implement some of the 
drag methods:
	OnDragEnter()
	OnDragOver()
	OnDragLeave()
	OnDrop().
	And, of course, don't forget to initialize OLE.

	Yury Kosov
	CoreTek, Inc.
	yury@msn.com
	
-----From: Lev Gloukhenki 

 DAOVIEW  from MSVC 4.x samples is a good example how to implement
drag'n'dop from/in CTree/CListControl using OLE 2 uniform data transfer

Lev Gloukhenki
lev@shira.co.il

-----From: Olav Beisland 

There's an example of how to do this in Microsoft's Softlib called Mfcdrag (Mfcdrag.exe 36508 bytes).





Sundar Narasimhan -- sundar@ai.mit.edu
Friday, August 30, 1996

   in the sample project CMNCTRLS, I have seen how to program drag and drop
   inside a CTreeCtrl. That was ugly. To make my life even more complicated,
   I'd like to know how to drag'n'drop from a CTreeCtrl into something else,
   maybe another CTreeCtrl, maybe an edit control, maybe even another
   application (OLE?). 

   Does anyone know how to do it?
Look at the documentation for CImageList. A clean way to do drag-drop is to
store object pointers in the 32-bit values associated with an item,
and mixin a drag-drop protocol into these objects. Separating the
drag-drop protocol into an "ask", "drop" and "reverse" protocol
usually results in fewer lines of code. Target highlighting can happen
inside of and in response to the "ask" and the reverse is useful to
implement "visitor" patterns to avoid coupling your drag-source and
target header files.

Hope that helps.








| Вернуться в корень Архива |