摘要:在分析MFC庫現有拖放框架的基礎上,建立了一套應用程序內的通用拖放框架,明確了拖放過程中參與者以及參與者之間的交互。實現針對應用程序內拖放的更靈活適用的拖放框架。并通過一個示例展示了拖放的效果。
關鍵詞:MFC;C++;拖放;拖放管理器;接口
中圖分類號:TP311文獻標識碼:A 文章編號:1009-3044(2010)01-218-02
The Implement of a Gerneral Drag-Drop Manager in Application
LI Jin-hua, YANG Fu-qin, DUAN Zhi-jian, LIU Wen-kai
(The Academy of Military Transport PLA., Tianjin 300161, China)
Abstract: After analyzing the current drag-drop frame of MFC, a gerneral grag-drop frame of application is proposed. The participator and the interaction between participators during a process of drag-drop operation is assigned. And the effect of drag-drop operation is show as an example.
Key words: Drag-Drop; DragDrop manager; C++; interface; MFC
對象拖放是指對某一指定的對象,利用鼠標拖動的方法,在不同應用程序的窗口之間、同一應用程序的不同窗口之間或同一應用程序的同一窗口內進行移動、復制(粘貼)等操作的技術。利用對象拖放,可以為用戶提供方便、直觀的操作界面。但是程序員要實現拖放,要考慮鼠標捕捉、窗口坐標轉換、拖放過程中鼠標的消息、拖放狀態的轉換等諸多因素,存在諸多難點。
MFC庫通過COleDataSource類、COleDataTarget類、COleDataObject類和CView類內置了一套支持拖放操作的架構,但是該框架主要是面向跨應用程序的文件拖放而實現的,不太適合在同一進程內任意內存對象的拖放,比如不直接支持動態顯示任意的拖放圖標、拖放源和拖放目標必須要從CView類繼承、依賴于復雜的OLE機制等。
本文基于MFC庫,脫離現有的拖放架構,建立了一個進程內的通用拖放管理架構,以實現應用程序內任意的兩個窗口對象之間的任意對象的拖放操作,具有自定義的圖標顯示、拖放指示和靈活的可擴展性等特性。通過重用該模塊,可以輕易實現具有直觀有效的拖放功能的用戶界面,提高開發質量和效率。
1 拖放相關機制
1.1 鼠標捕捉和坐標轉換
拖放操作首先需要捕捉鼠標,使用::SetCapture(HWND hWnd)函數和::ReleaseCapture()函數對鼠標進行捕捉和釋放。一旦捕捉后,所有的鼠標消息將發往hWnd所指定的窗口對象。
捕捉后鼠標消息中包含的坐標值都是相對于捕捉窗口的。鼠標移動到拖放目標窗口時,拖放管理器需要將相對于捕捉窗口的坐標轉換為拖放目標窗口的坐標,并調用拖放目標窗口的OnDragOver(CDragData dragData, const CPoint point)函數。拖放管理器自動完成這個轉換。轉換的方法是先調用::ClientToScreen()函數轉換到屏幕坐標,然后再調用::ScreenToClient()函數轉換為拖放目標窗口的坐標。
1.2拖放圖標顯示
拖放中的圖標顯示使用CImageList類。相關的成員函數如下:
CImageList::BeginDrag(CWnd* pWndLock, CPoint point)函數開始圖像的拖動;
CImageList::DragMove( )函數顯示拖放中的圖標,即一個半透明的圖標并隨鼠標的移動而移動;
CImageList::EndDrag( )結束本次拖放顯示。
拖放中鼠標距離所顯示的圖標的左上角的坐標點稱為熱點(hotspot)。拖放中的圖標總是以熱點為基點隨鼠標的移動而移動。
CImageList中的圖像通常由拖放源來創建,如果沒有創建的話,拖放管理器將創建一個默認圖標,并設置熱點坐標為CPoint(8, 8)。
1.3拖放范圍
拖放的范圍是一個限制拖放操作范圍的窗口對象,超出這個范圍,拖放的圖標將不再顯示。這個拖放范圍是通過調用CImageList::BeginDrag函數中的pWndLock參數注冊。這個工作由拖放管理器自動完成。
1.4 拖放回調接口IDragGrop
每個涉及到拖放操作的窗口對象都必須實現IDragGrop接口,拖放管理器通過該接口與拖放源和拖放目標進行交互。IDragGrop接口的定義如圖1。
OnDragEnter接口函數由拖放管理器在拖放激活時對拖放源窗口調用。拖放源窗口通常根據傳遞的鼠標坐標點判斷何對象被選中,如果有合法的對象,則生成該對象的顯示圖標以及設定鼠標熱點坐標,向dragData注冊該對象并返回true。返回1則終止拖放。如果不生成圖標,則拖放管理器使用內部缺省的圖標。
OnDragOver接口函數在拖放圖標進入拖放目標窗口時被調用。此函數的返回值決定了拖放過程中光標的顯示類型,如果返回true,則光標顯示為接受型;如果返回1,則光標顯示為拒絕接受型。
OnDrop接口函數在用戶釋放鼠標左鍵的時候,由管理器對拖放目標窗口調用。拖放目標窗口判斷被拖動的對象及相關信息,更新內部相應的記錄并返回true。返回1表示接受拖放對象失敗。返回值被傳遞到接下來調用OnDragEnd函數的bAbort參數。
OnDragEnd接口函數在用戶釋放鼠標左鍵、對拖放目標窗口OnDrop調用之后,由管理器對拖放源窗口調用。拖放源窗口根據bAbort參數判斷拖放過程是否正常完成,如果正常完成,則釋放被拖放對象的相關數據結構。
1.5 拖放數據對象CDragData
拖放數據對象CDragData主要保存拖放的數據,包括拖放源、當前的拖放目標窗口、當前的拖放圖像、拖放熱點以及其它的任意數據。拖放源以及拖放目標均可向CDragData訪問和添加任意的數據,比如字節流、指針等。CDragData類的聲明如圖2所示。
m_otherData字段是一個動態的字節流的數組。用于保存拖放源、拖放目標所訪問和添加的任意數據。每項數據都有唯一的字符串ID,通過該數據類型,等于實現了一個簡單的拖放協議。
2 拖放管理器的處理邏輯
2.1 拖放管理器的初始化調用注冊拖放范圍的成員函數Create(CWnd * pHost)。調用向拖放管理器注冊回調接口的成員函數Add(IDragDrop * pDD)。拖放源窗口和拖放目標窗口都需要向拖放管理器注冊它們的回調接口。如果拖放目標窗口只接受“放”的操作而不允許“拖”的話,可以在OnDragEnter實現中返回1。
2.2拖放動作的激發及拖放處理引擎
拖放源調用拖放管理器的OnLButtonDown函數激發拖放循環。在拖放管理器的OnLButtonDown函數中,建立了一個消息泵。核心代碼如下:
for (;;)
{
MSG msg;
if (::GetMessage(msg, NULL, 0, 0) != TRUE ||
::GetCapture() != m_hwndDragging)
break;
switch (msg.message)
{ case WM_LBUTTONUP:
OnLButtonUp(msg);//處理拖放結束邏輯
break;
case WM_MOUSEMOVE:
OnMouseMove(msg); //拖放顯示
break;
case WM_KEYDOWN:
if (msg.wParam == VK_ESCAPE m_iState)
{ //響應退出消息
pDragSource->OnDragEnd(true, m_oDragData);
SetState(NONE);
} else
DispatchMessage(msg);
break;
default:
DispatchMessage(msg);
break;
}
if (m_iState == NONE)
break;
}
2.3 拖放
流程及與回調接口的交互拖放管理器被激發后進入拖放控制流程,拖放管理器根據用戶控制的鼠標移動來分別對拖放源和拖放目標進行回調。以CDragData為媒介,拖放源與拖放目標進行相互的交互,最終達到拖放數據交換的目的。具體的流程如圖3所示。
3 結束語
該文建立了一個進程內通用的拖放管理器框架,包含可任意擴展的拖放數據類、精心設計的IDragDrop回調接口和一套完整的實現。拖放源和拖放目標只要實現IDragDrop接口,就可實現復雜的拖放操作。具體的拖放實現細節,包括拖放圖標的顯示、坐標的轉換、拖放中途的退出、拖放狀態的轉換等均由拖放管理器完成。通過CDragData類實現了拖放源與拖放目標的交互。
相比MFC中所支持的拖放框架,本文建立的框架具有拖放圖片的可定制、不需要從CView類繼承、拖放過程不需要用戶關心等特點,具有更強的適應性。
圖4所示為某一航空配載系統中車輛裝備配載的拖放配載界面,其內部實現是采用本文中的拖放管理器框架。拖放過程中光標形狀提示了是否能放下該對象。程序在VS2005開發環境下開發,編譯運行通過。
參考文獻:
[1] Microsoft Corporation.MSDN Liarary[M]. Microsoft Corporation,2008.
[2] Microsoft Corporation.MFC[CP].Microsoft Corporation,2005.
[3] 辛長安,梅林.VC++編程技術與難點剖析[M].海口:南方出版社,2004.