<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    創建客戶區窗口,列表框之間項的拖拽操作

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    我寫了一個小類庫,其中包含一個類,CDragDropMgr,用這個類可以在自己的應用程序窗口間添加拖拽行為。我還寫了一個測試程序,DDTest,示范了如何使用 CDragDropMgr 類(參見 Figure 2)。Figure 3 是程序運行的畫面。DDTest 有兩個列表框和一個編輯框。你可以將第一個列表框中的項目拖拽到第二個列表框,或者編輯框。此外,你還能在第二個列表框里通過拖拽重排項目。DDTest 就是使用 CDragDropMgr 來實現上述這些功能的。下面我首先示范如何使用 CDragDropMgr,然后在探討它的工作原理。

    RFID設備管理軟件

      Figure 3 運行中的 DDTest

      為了使用拖拽管理器,首先要在主窗口或對話框中實例化 CDragDropMgr,然后用一個表對之進行初始化,就像下面的代碼這樣:

    雙擊代碼全選 1 2 3 4 5 6 7 static DRAGDROPWND MyDragDropWindows[] = {   { IDC_LIST1, DDW_SOURCE },   { IDC_LIST2, DDW_SOURCE|DDW_TARGET },   { IDC_EDIT1, DDW_TARGET },   { 0, 0 }, }; m_ddm.Install(this, MyDragDropWindows);  

      我的專欄的愛好者們知道我編程的五大秘訣之一便是 一張表勝過一千行代碼。表的形式比長長的一串過程代碼更加簡練、優雅、可靠和可維護。在本文的例子中,表告訴拖拽管理器哪個子窗口是拖拽操作的源和/或目標。每一個表入口都有一個子窗口ID以及一個 DDW_SOURCE 和 DDW_TARGET 的組合標志。在 DDTest 中,第一個列表框是源,第二個列表框既可以是源,也可以是目標,編輯框只能是目標。但是不管怎么樣,不要忘了在表的末尾加上 NULL!

      一旦你用窗口表對拖拽管理器進行了初始化,下一步便是改寫主窗口的 PreTranslateMessage 函數以便將消息傳遞給拖拽管理器:

    雙擊代碼全選 1 2 3 4 5 BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) {   return m_ddm.PreTranslateMessage(pMsg) ? TRUE :    CDialog::PreTranslateMessage(pMsg); }

      一切準備就緒,當用戶試圖從一個窗口到另一個窗口實施拖拽操作時,拖拽管理器便會察覺到并通知應用程序要做相應的處理。CDragDropMgr 可以發送四個消息/通知:WM_DD_DRAGENTER、WM_DD_DRAGOVER、WM_DD_ DRAGDROP 和 WM_DD_DRAGABORT。收到這些消息/通知后,做什么樣的處理由你來決定。WM_DD_DRAGENTER 和 WM_DD_DRAGDROP 是拖拽操作必須要做的處理。其它兩個可選。WM_DD_DRAGABORT 用來處理用戶取消操作時的清除工作。WM_DD_ DRAGOVER 使你能夠在用戶實施拖拽操作而移動鼠標時進行連續不斷的處理。DDTest 這樣簡單的程序不需要處理這些消息。

      當拖拽管理器發送 WM_DD_DRAGENTER 消息時,它在 LPARAM 中傳遞一個 DRAGDROPINFO 結構。你的任務是將 DRAGDROPINFO::data 指向一個包含你想要拖拽數據的 CDragDropData 實例,然后返回 TRUE。如果拖拽是不允許的(也許用戶單擊了列表框中的某個死區(dead area))則應該返回 FALSE,并不要設置 DRAGDROPINFO::data,CDragDropData 類似 COM 的 IDataObject,但要簡單得多:它保存擬拽動的數據。CDragDropData 有三個虛擬函數:OnGetDragSize 獲得一個拖拽圖像的綁定矩形,OnDrawData 繪制拖拽圖像,OnGetData 獲取數據本身。我在我的庫中提供了一個叫 CDragDropText 的類,它實現了這些函數,用來處理文本拖拽操作。它將文本保存在一個 CString 中。OnGetData 返回這個串,OnGetDragSize 計算該文本矩形,OnDrawData 則繪制該文本:

    雙擊代碼全選 1 2 3 4 void CDragDropText::OnDrawData(CDC& dc, CRect& rc) {  dc.DrawText(m_text, &rc, DT_LEFT|DT_END_ELLIPSIS); }   

      如果你想得到這個文本,你唯一需要調用的函數是 OnGetData,拖拽管理器需要時在其內部調用 OnGetDragSize 和 OnDrawData。

      那么所有這些工作是如何實現的呢?當 DDTest 收到 WM_DD_DRAGENTER 消息,它調用一個內部函數 GetLBItemUnderPt 來確定光標下是哪個列表框(如果有的話)。然后 DDTest 以這一項的文本作為數據創建一個 CDragDropText 對象并將 DRAGDROPINFO 中的 data 指針指向該對象:

    雙擊代碼全選 1 2 3 4 5 6 7 8 9 // in CMyDlg::OnDragEnter DRAGDROPINFO& ddi = *(DRAGDROPINFO*)lp; int item = GetLBItemUnderPt(...); if (item>=0) {  CString text = // get item text  ddi.data = new CDragDropText(text);  return TRUE;  // allow drag-drop } return FALSE; // nothing to drag   

      由 CDragDropMgr 來做剩余的工作。當用戶拖拽它時在周邊繪制文本并根據光標是否出于拖拽目的地上方而相應地改變鼠標光標。

      當用戶松開鼠標,CDragDropMgr 便給應用程序發送一個 WM_DD_DRAGDROP 消息。暗示數據已經拖拽完成。對于 DDTest 而言,這意味著如果鼠標出于編輯框上方,則要設置編輯框中的文本,或者如果鼠標是在列表框上方,則要將文本添加到列表框中。在真正實現中,DDTest 稍顯復雜,因為它可以讓用戶重新安排第二個列表框中的項目。DDTest 有代碼可以察覺是否需要添加文本或修改列表框中文本的位置。具體細節就留給你來做了,OnDragDrop 實現的基本要點都是一樣的:

    雙擊代碼全選 1 2 3 4 5 // OnDragDrop handler DRAGDROPINFO& ddi = *(DRAGDROPINFO*)lp; void* data = ddi.data->OnGetData(); // do something with data return 0;   

      以上都是關于文本的操作,如果要拖拽其它類型的數據怎么辦呢?為此,你必須通過 CDragDropData 派生并改寫三個基本函數來擴展我的庫。例如,為了拖拽圖像,你得派生一個 CDragDropImage 類,在這個類中,OnGetData 返回 BITMAP 或 CBitmap,OnGetDragSize 返回位圖的尺寸,OnDrawData 調用 BltBit 或其它什么函數來繪制該位圖。

      我已經示范了 CDragDropMgr 的使用方法,但它是如何工作的呢?基本思路很簡單。CDragDropMgr::PreTranslateMessage 查找發送到拖拽源窗口之一的鼠標消息并發送相應的通知到你的應用程序主窗口。CDragDropMgr 實現了一個典型的具有三種狀態的有限狀態機:NONE、CAPTURED 和 DRAGGING。當用戶按下鼠標鍵,CDragDropMgr 進入 CAPTURED 狀態。當用戶移動鼠標,則進入 DRAGGING 狀態。具體細節簡單直白。

      CDragDropMgr 使用 PreTranslateMessage 而不是子類化主窗口,因為它需要解釋發送到可能的拖拽源窗口之一鼠標消息,該拖拽源窗口由前述的拖拽窗口表確定。MFC 的優點之一是它在主窗口中僅通過虛擬 PreTranslateMessage 方法便可以過濾所有子窗口消息。這使得 CDragDropMgr 可以僅在單一的函數中便可截獲發送到任何潛在拖拽源窗口的鼠標消息,從而避免了必須子類化每一個窗口。當 CDragDropMgr::PreTranslateMessage 看到 WM_LBUTTONDOWN,它便查找該窗口句柄(HWND)以便檢查它是否被列入源窗口表。如果它是一個源窗口,則進行拖拽初始化,否則忽略該消息。

      拖拽數據的機制是很簡單直白的,甚至有些單調無趣,所以細節我就不再贅言。唯一一個亮點是 CDragDropData 使用 CImageList 來繪畫。如果你實現自己的拖拽管理器,我鼓勵你也這么做,CImageList 包含如下幾個函數:BeginDrag、DragEnter、DragMove 和 EndDrag,用它們可以很快解決比特繪畫問題,它們使用特有的光柵操作使圖像呈半透明,從其以前位置擦除等等。

      沒有 CImageList,這些繪制細節冗長乏味。有了它,CDragDropMgr 只要將拖拽圖像繪制到圖像列表位圖一次即可。當用戶初始化拖拽操作時,CDragDropMgr 通知主應用程序,該主應用程序將 DRAGDROPINFO::data 設置為一個 CDragDropData,正如我前面描述的那樣。然后拖拽管理器調用 CDragDropData:: CreateDragImage (參見 Figure 4),它創建一個包含要繪制的圖像列表。CreateDragImage 調用虛擬函數 CDragDropData::OnGetDragSize 來獲取拖拽圖像的尺寸,CDragDropData::OnDrawData 將數據繪制到圖像列表的位圖中。一旦完成了些工作,CDragDropMgr 調用圖像列表函數繪制拖拽期間的圖像。例如,每次用戶移動鼠標,CDragDropMgr 都調用 CImageList::DragMove。還有比這更容易的嗎?其優美之處在于這個代碼完全是通用的。為了處理新的數據類型,你只要實現 OnGetDragSize 和 OnDrawData 即可。

    本文示例代碼或素材下載

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全