程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> 在切分窗口之間實現拖放

在切分窗口之間實現拖放

編輯:vc教程

  在許多象資源管理器界面風格的應用程序中,很多的情況下要用到在不同的視之間的拖放操作。本文就具體給出了實現方法,望能給讀者一參考。(本文中用到的工程是左邊具有目錄樹視、右邊具有列表視)

  首先,兩個視都應該有它們自己的實現函數來進行拖放操作。只要不設置"SetCapture/ReleaseCapture",被拖放的條目就能從原來的視拖放到目的視。如果被拖的條目(鼠標下的)離開了原來的視,那麼目的視的ON_WM_MOUSEMOVE()-消息就獲得了該條目的控制條件。所以我們必須保證不同的視(原來的視以及目的視)能訪問相同的成員變量,從而可以在app類裡面定義。
接下來,我們就在app類裡面定義一些成員變量:

public:
//拖放成員變量:
CImageList *cpDragImage;
BOOL cDragging;
CWnd *cpDragWnd;
CWnd *cpDropWnd;
HTREEITEM cTreeItemDrag;
HTREEITEM cTreeItemDrop;
int cListItemDragIndex;
int cListItemDropIndex;
CPoint cDropPoint;
//列表視需要一個全局變量來驗證目標的位置

  好,我們現在來完成我們的主框架類:

  為了能從列表視訪問目錄樹視,我們用到了一個小小的幫助函數(但是如果你在項目向導裡選擇了"資源管理器風格"的話, "GetRightPane()"就不用在定義了)

CMyListVIEw* CMainFrame::GetRightPane()
{
 CWnd* pWnd = m_wndSplitter.GetPane(0, 1);
 CMyListView* pView = DYNAMIC_DOWNCAST(CMyListVIEw, pWnd);
 return pVIEw;
}

CMyTreeVIEw* CMainFrame::GetLeFTPane()
{
 CWnd* pWnd = m_wndSplitter.GetPane(0, 0);
 CMyTreeView *pTree = DYNAMIC_DOWNCAST(CMyTreeVIEw, pWnd);
 return pTree;
}

  現在到目錄樹視了:

  為了能訪問需要的成員變量,我們還是先定義了一個幫助函數從而可以輕易的訪問我們的app類:

CMyApp *CMyTreeVIEw::GetApp()
{
 return ( (CMyApp*)AfxGetApp() );
}

  三個消息處理函數:

ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)

  把這個視所能設置的元素都設成是開始拖的狀態,而目的視也許是本身,或是別的視。

void CMyTreeVIEw::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
 NM_TREEVIEW *pTreeView = (NM_TREEVIEW*)pNMHDR;

 *pResult = 0;

 //獲得指向樹型控件的指針:
 CTreeCtrl &cTree = GetTreeCtrl();

 GetApp()->cTreeItemDrag = pTreeVIEw->itemNew.hItem;
 GetApp()->cTreeItemDrop = NULL;

 //建立一個被拖的條目的圖象:
 GetApp()->cpDragImage = cTree.CreateDragImage(GetApp()->cTreeItemDrag);
 GetApp()->cpDragImage->BeginDrag(0, CPoint(-15,-15));
 POINT pt = pTreeVIEw->ptDrag;
 ClIEntToScreen( &pt );
 GetApp()->cpDragImage->DragEnter(NULL, pt);

 //初始化:
 GetApp()->cDragging = TRUE;
 GetApp()->cpDragWnd = &cTree;
 GetApp()->cpDropWnd = NULL;
 }

void CMyTreeVIEw::OnMouseMove(UINT nFlags, CPoint point)
{
 HTREEITEM hitem;
 UINT flags;

 //獲得指向樹型控件的指針:
 CTreeCtrl &cTree = GetTreeCtrl();

 //如果是正在被拖動的話:
 if ( GetApp()->cDragging )
 {
  POINT pt = point;
  ClIEntToScreen( &pt );

  //移動圖象:
  GetApp()->cpDragImage->DragMove(pt);
 
  if ( (hitem = cTree.HitTest(point, &flags)) != NULL )
  {
   GetApp()->cpDragImage->DragShowNolock(FALSE);
   cTree.SelectDropTarget(hitem);
   GetApp()->cTreeItemDrop = hitem;
   GetApp()->cpDragImage->DragShowNolock(TRUE);
  }
 }

 CTreeVIEw::OnMouseMove(nFlags, point);
}

void CMyTreeVIEw::OnLButtonUp(UINT nFlags, CPoint point)
{
 //獲得指向樹型控件的指針:
 CTreeCtrl &cTree = GetTreeCtrl();

 CTreeVIEw::OnLButtonUp(nFlags, point);

 //I如果是正在被拖動的話:
 if ( GetApp()->cDragging )
 {
  //不再拖動了:
  GetApp()->cDragging = FALSE;
  GetApp()->cpDragImage->DragLeave(this);
  GetApp()->cpDragImage->EndDrag();
  delete GetApp()->cpDragImage;

  cTree.SelectDropTarget(NULL);

  //驗證被拖動的圖象已被放下:
  GetApp()->cDropPoint = point;
  ClIEntToScreen(&GetApp()->cDropPoint);
  GetApp()->cpDropWnd = WindowFromPoint(GetApp()->cDropPoint);

  //選擇拖動目的資源的類型:
  if ( GetApp()->cpDragWnd->IsKindOf(RUNTIME_CLASS(CListVIEw)) )
  {
   AfxMessageBox("source is list vIEw", MB_OK);
  }
  else
   if ( GetApp()->cpDragWnd->IsKindOf(RUNTIME_CLASS(CTreeVIEw)) )
   {
    AfxMessageBox("source is treevIEw", MB_OK);
   }
   else
    AfxMessageBox("source is something else", MB_OK);
 }
}

  接下來就是到了列表視了,做法和前面的差不多:

CMyApp *CMyListVIEw::GetApp()
{
 return ( (CMyApp*)AfxGetApp() );
}

CMainFrame *CKAIVIEw::GetFrame()
{
  return ( ((CMainFrame*)GetParentFrame()) );
}


CMyTreeView *CMyListVIEw::GetTree()
{
 return ( GetFrame()->GetLeFTPane() );
}

  三個消息處理函數:

ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)

  把這個視所能設置的元素都設成是開始拖的狀態,而目的視也許是本身,或是別的視。

void CMyListVIEw::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

 *pResult = 0;

 //獲得指向列表控件的指針:
 CListCtrl &cList = GetListCtrl();

 //設置拖動資源:
 GetApp()->cListItemDragIndex = ((NM_LISTVIEW *)pNMHDR)->iItem;

 //建立一個被拖的條目的圖象:
 POINT pt;
 pt.x = pt.y = 8;
 GetApp()->cpDragImage = cList.CreateDragImage(GetApp()->cListItemDragIndex, &pt);
 GetApp()->cpDragImage->BeginDrag(0, CPoint (8, 8));
 pt = ((NM_LISTVIEW *)pNMHDR)->ptAction;
 ClIEntToScreen( &pt );
 GetApp()->cpDragImage->DragEnter(NULL, pt);

 //初始化:
 GetApp()->cDragging = TRUE;
 GetApp()->cListItemDropIndex = -1;
 GetApp()->cpDragWnd = &cList;
 GetApp()->cpDropWnd = NULL;
 }

void CMyListVIEw::OnMouseMove(UINT nFlags, CPoint point)
{
 //如果是正在被拖動的話
 if( GetApp()->cDragging )
 {
  POINT pt = point;
  ClIEntToScreen(&pt);

  //移動圖象:
  GetApp()->cpDragImage->DragMove(pt);

  //獲得被放置的窗口:
  GetApp()->cpDragImage->DragShowNolock(FALSE);
  GetApp()->cpDropWnd = WindowFromPoint(pt);
  GetApp()->cpDropWnd->ScreenToClIEnt(&pt);
  GetApp()->cpDragImage->DragShowNolock(TRUE);

  //獲得樹型控件:
  CTreeCtrl &cTree = GetTree()->GetTreeCtrl();

  cTree.SelectDropTarget(NULL);
 }

 CListVIEw::OnMouseMove(nFlags, point);
}

void CMyListVIEw::OnLButtonUp(UINT nFlags, CPoint point)
{
 //如果是正在被拖動的話:
 if( GetApp()->cDragging )
 {
  //結束拖動:
  GetApp()->cDragging = FALSE;
  GetApp()->cpDragImage->DragLeave(GetDesktopWindow());
  GetApp()->cpDragImage->EndDrag();

  //獲得放置點的窗口:
  GetApp()->cDropPoint = point;
  ClIEntToScreen(&GetApp()->cDropPoint);
  GetApp()->cpDropWnd = WindowFromPoint(GetApp()->cDropPoint);

  //如果目的資源是本身的話就取消:

  //選擇拖動目的資源的類型:
  if ( GetApp()->cpDragWnd->IsKindOf(RUNTIME_CLASS(CListVIEw)) )
  {
   AfxMessageBox("source is list vIEw", MB_OK);
   }
  else
   if ( GetApp()->cpDragWnd->IsKindOf(RUNTIME_CLASS(CTreeVIEw)) )
   {
    AfxMessageBox("source is treevIEw", MB_OK);
   }
 else
  AfxMessageBox("source is something else", MB_OK);
}

CListVIEw::OnLButtonUp(nFlags, point);
}

  好了,到此為止,我們已經做好了所有的工作,可以實現在不同的視之間的拖動操作了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved