青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

幽幽
 
posts - 51,  comments - 28,  trackbacks - 0

OLE拖放實現(xiàn)

MFC本身的CView類是支持拖放操作的,通過研究CView類的源碼,大體知道它的實現(xiàn)原理是這樣的:CView類中有一個COleDropTarget類的對象,在視圖窗口初始化時,調用COleDropTarget類成員函數(shù)Register(),以此在系統(tǒng)中注冊該視圖窗口為拖放接收窗口。當進行拖放操作的鼠標指針處于視圖窗口范圍內時,COleDropTarge類會做出反應,它的OnDragEnterOnDragOverOnDropExOnDrop等成員函數(shù)被依次調用,這些函數(shù)默認均是調用與其相對應的CView類成員函數(shù)OnDragEnterOnDragOverOnDropExOnDrop等,程序員只需重載這些CView類成員函數(shù),即可對拖動的過程及結果進行控制。

因為COleDropTarget默認只對CView提供支持,所以如果要讓其他的窗口支持拖放,我們必須同時對要支持拖放的窗口類和COleDropTarget類進行派生。把對拖放操作具體進行處理的代碼封裝成派生窗口類的成員函數(shù),然后重載COleDropTarget中對應的五個虛函數(shù),當它接收到拖放動作時,調用窗口派生類的處理函數(shù)即可。但這里有一個問題,就是我們怎么知道何時調用派生類的處理函數(shù)呢?答案是運用RTTI技術。如果COleDropTarget派生類收到的窗口指針類型,就是我們派生的窗口類,那么就調用它的處理函數(shù),否則調用基類進行處理。

首先生成一個對話框工程,添加二個新類。

第一個類名為CListCtrlEx,父類為CListCtrl。添加完畢后,在CListCtrlEx的定義頭文件中加入DECLARE_DYNAMIC(CListCtrlEx),在其實現(xiàn)文件中加入IMPLEMENT_DYNAMIC(CListCtrlEx,CListCtrl),這樣就對CListCtrlEx類添加了RTTI運行期類型識別(Run Time Type Information)支持。

第二個類名為COleDropTargetEx,父類為COleDataTarget

CListCtrlEx中添加COleDropTargetEx類的對象,并添加下列公有虛函數(shù)的聲明:

       virtual BOOL Initialize();

       virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);

       virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, DROPEFFECT dropList, CPoint point);

       virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);

       virtual void OnDragLeave(CWnd* pWnd);

Initialize函數(shù)用于注冊CListCtrlEx成為拖放接收窗口;

OnDragOver在拖放鼠標進入窗口時被調用。此函數(shù)的返回值決定了后續(xù)的動作的類型:如果返回DROPEFFECT_MOVE,則產(chǎn)生一個剪切動作;如果返回DROPEFFECT_COPY,則產(chǎn)生一個復制動作,如果返回DROPEFFECT_NONE,則不會產(chǎn)生拖放動作,因為OnDropExOnDrop函數(shù)將不會被調用(OnDragLeave函數(shù)仍會被調用)。

OnDropEx函數(shù)會在OnDrop函數(shù)之前調用,如果OnDropEx函數(shù)沒有對拖放動作進行處理,則應用程序框架會接著調用OnDrop函數(shù)進行處理。所以必須要在派生類中重載OnDropEx函數(shù)——即使什么動作都都沒有做——否則我們的OnDrop函數(shù)將不會被執(zhí)行到,因為沒有重載的話,將會調用基類的OnDropEx函數(shù),而基類的OnDropEx函數(shù)對拖放是進行了處理的——盡管不是我們所想要的動作。當然你也可以把對拖放進行處理的動作放在OnDropEx中——那樣就不需要重載OnDrop了。

OnDragLeave函數(shù)會在鼠標離開窗口時被調用,在此可以進行一些簡單的清理工作。譬如在OnDragEnter或者OnDragOver函數(shù)中,我們改變了光標的形態(tài),那么此時我們就應該把光標恢復過來。

這些函數(shù)中最重要的是OnDrop函數(shù),拖放動作將在此進行處理,它的全部源碼如下:

BOOL CListCtrlEx::OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)

{

       UINT              nFileCount = 0;

       HDROP           hDropFiles = NULL;

       HGLOBAL        hMemData = NULL;

 

       AfxMessageBox("OnDrop");

       if(pDataObject->IsDataAvailable(CF_HDROP))

       {

              hMemData = pDataObject->GetGlobalData(CF_HDROP);

              hDropFiles = (HDROP)GlobalLock((HGLOBAL)hMemData); //鎖定內存塊

              if(hDropFiles != NULL)

              {

                     char chTemp[_MAX_PATH+1] = {0};

                     nFileCount = DragQueryFile(hDropFiles, 0xFFFFFFFF, NULL, 0);

                     for(UINT nCur=0; nCur<nFileCount; ++nCur) //遍歷取得每個文件名

                     {

                            ZeroMemory(chTemp, _MAX_PATH+1);

                DragQueryFile(hDropFiles, nCur, (LPTSTR)chTemp, _MAX_PATH+1);

                            AddAllFiles(chTemp);

                     }

              }

              GlobalUnlock(hMemData);

              return TRUE;

       }

       else

       {

              return FALSE;

       }

}

在第二個類COleDropTarget中添加如下對應的函數(shù):

    virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);

    virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);

       virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, DROPEFFECT dropList, CPoint point);

       virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);

       virtual void OnDragLeave(CWnd* pWnd);

它們的動作都差不多:先用RTTI判斷窗口指針pWnd的類型,如果是CListCtrlEx,則調用CListCtrlEx中對應的處理函數(shù),否則調用基類的處理函數(shù)。以OnDrop為例:

BOOL COleDropTargetEx::OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)

{

       CListCtrlEx*     pListCtrlEx = NULL;

      

       ASSERT_VALID(this);

       ASSERT(IsWindow(pWnd->m_hWnd));

      

       if(pWnd->IsKindOf(RUNTIME_CLASS(CListCtrlEx)))

       {

              pListCtrlEx = (CListCtrlEx*)pWnd;

              return pListCtrlEx->OnDrop(pWnd, pDataObject, dropEffect, point);

       }

       else

       {

              return COleDropTarget::OnDrop(pWnd, pDataObject, dropEffect, point);    

       }

}

 

//倒霉的64K限制,只能再截斷了:(

至此,我們成功地為CListCtrlEx添加了文件拖入操作的支持。一個完整的拖放操作,還包括拖出動作,所以必須要為該類再添加拖出操作,即,將列表中的某一項或者多項拖出成為一個文件。這就需要用到另一個類:COleDataSource。具體步驟如下:

CListCtrlEx中加入一個COleDataSource的實例,并映射列表框的LVN_BEGINDRAG消息處理函數(shù),在此我們添加拖出操作的代碼。

實現(xiàn)拖出非常簡單,只需要依次調用COleDataSource的三個函數(shù)即可:Empty用于清空原先對象中緩存的數(shù)據(jù),CacheGlobalData用來緩存數(shù)據(jù)以進行拖放操作,最后調用DoDragDrop啟動本次拖放操作。

但在調用之前,必須要做一些準備工作。主要的任務就是創(chuàng)建一個DROPFILES結構體,并拷貝要拖放的文件名到結構體后的內存中。DROPFILES結構體定義了CF_HDROP剪貼板格式,緊跟它后面的是一系列被拖放文件的路徑名。它的定義如下:

typedef struct _DROPFILES

{

    DWORD     pFiles;  //文件名起始地址

    POINT      pt;     //鼠標放下的位置,坐標由fNC成員指定

    BOOL        fNC;    //TRUE表示適用屏幕坐標系,否則使用客戶坐標系

    BOOL        fWide;  //文件名字符串是否使用寬字符

} DROPFILES, FAR* LPDROPFILES;

拖放之前的準備動作的代碼如下:

uBufferSize = sizeof(DROPFILES) + uBufferSize + 1;

    hMemData = GlobalAlloc(GPTR,uBufferSize);

    ASSERT(hMemData != NULL);

      

       lpDropFiles = (LPDROPFILES)GlobalLock(hMemData); //鎖定之,并設置相關成員

       ASSERT(lpDropFiles != NULL);

       lpDropFiles->pFiles = sizeof(DROPFILES);

#ifdef _UNICODE

       lpDropFiles->fWide = TRUE;

#else

       lpDropFiles->fWide = FALSE;

#endif

 

       //把選中的所有文件名依次復制到DROPFILES結構體后面(全局內存中)

       pItemPos = strSelectedList.GetHeadPosition();

       pszStart = (char*)((LPBYTE)lpDropFiles + sizeof(DROPFILES));

       while(pItemPos != NULL)

       {

              lstrcpy(pszStart, (LPCTSTR)strSelectedList.GetNext(pItemPos));

        pszStart = strchr(pszStart,'\0') + 1; //下次的起始位置是上一次結尾+1

       }

準備完畢之后就可以進行拖放了,拖放動作有DoDragDrop函數(shù)觸發(fā),其原型如下:

DROPEFFECT DoDragDrop(

DWORD dwEffects = DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK, LPCRECT lpRectStartDrag = NULL,

COleDropSource* pDropSource = NULL

);

這里,dwEffects指定了允許施加于本COleDataSource實例之上的動作集:剪切、復制或無動作。

    lpRectStartDrag指示拖放操作真正開始的矩形,如果鼠標沒有移出該矩形,則拖放操作視作放棄處理。如果本成員設為NULL,則該起始矩形將為一個像素大小。

    pDropSource表明拖放所使用的COleDataSource對象。

而該函數(shù)的返回值,則表明本次拖放操作所實際產(chǎn)生的效果,至于具體產(chǎn)生何種效果,則由系統(tǒng)決定。譬如在拖放時按住Shift鍵,將產(chǎn)生剪切效果;按住Ctrl鍵,將產(chǎn)生復制效果,等等。

拖放的代碼如下:

       m_oleDataSource.Empty();

       m_oleDataSource.CacheGlobalData(CF_HDROP, hMemData);

       DropResult = m_oleDataSource.DoDragDrop(DROPEFFECT_MOVE|DROPEFFECT_COPY);

最后一點要注意的是,在Windows NT 4.0以上的系統(tǒng)中,即使實際產(chǎn)生的是DROPEFFECT_MOVE動作,DoDragDrop函數(shù)也只返回DROPEFFECT_NONE。產(chǎn)生這個問題的原因在于,Windows NT 4.0Shell會直接移動文件本身來對移動操作進行優(yōu)化。返回值DROPEFFECT_MOVE最初的含義,就是通知執(zhí)行拖放操作的應用程序去刪除原位置上的文件。但是因為Shell已經(jīng)替應用程序完成了這個(刪除)動作,所以,函數(shù)返回DROPEFFECT_NONE。要想知道文件是否真的被移動了也很簡單,只要在函數(shù)返回之后檢查一下原位置上的文件是否存在就可以了。

Windows 9x系列的操作系統(tǒng)也會對移動進行同樣的優(yōu)化動作,但是它不會返回DROPEFFECT_NONE來代替DROPEFFECT_MOVE。詳細的解釋參見MS知識庫Q182219

posted on 2008-08-14 19:19 幽幽 閱讀(3212) 評論(0)  編輯 收藏 引用 所屬分類: Windows

<2008年8月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

常用鏈接

留言簿(6)

隨筆分類(35)

隨筆檔案(51)

文章分類(3)

文章檔案(3)

相冊

我的鏈接

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            夜夜嗨av一区二区三区四区| 狠狠入ady亚洲精品| 99视频+国产日韩欧美| 老色鬼久久亚洲一区二区| 欧美一级在线亚洲天堂| 久久爱www.| 玖玖玖国产精品| 欧美黄色小视频| 欧美全黄视频| 国产精品视频yy9299一区| 国产视频丨精品|在线观看| 激情小说亚洲一区| 日韩西西人体444www| 亚洲在线网站| 久久久欧美精品sm网站| 欧美成人有码| 亚洲视频网站在线观看| 久久国产日韩欧美| 欧美成人午夜| 国产精品日韩欧美大师| 亚洲第一页中文字幕| 亚洲一区二区欧美| 久久在线播放| 国产精品99久久不卡二区| 久久激情五月丁香伊人| 欧美精品偷拍| 激情久久五月| 性刺激综合网| 亚洲国产欧美久久| 一区二区高清在线| 玖玖视频精品| 国产一区二区精品丝袜| 99精品视频免费| 噜噜噜噜噜久久久久久91| 99视频在线观看一区三区| 久久久久成人精品| 国产精品毛片在线| av成人激情| 欧美激情a∨在线视频播放| 亚洲一区二区在线播放| 欧美经典一区二区三区| 影音先锋久久精品| 久久国产免费| 一本一本a久久| 欧美精品久久久久久久免费观看| 很黄很黄激情成人| 久久精品一本| 校园激情久久| 国产亚洲精品aa午夜观看| 亚洲视频高清| 99在线视频精品| 欧美日韩国产精品成人| 日韩手机在线导航| 亚洲精品国产拍免费91在线| 每日更新成人在线视频| 亚洲国产精品久久久久秋霞蜜臀| 麻豆精品精品国产自在97香蕉| 久久国产手机看片| 亚洲成在线观看| 欧美美女操人视频| 国产精品一区毛片| 一区二区日韩| 99热在这里有精品免费| 欧美视频福利| 亚洲综合色网站| 中文国产成人精品久久一| 欧美日韩四区| 亚洲一品av免费观看| 亚洲天堂男人| 国产欧美大片| 久久久亚洲欧洲日产国码αv| 久久精品国产一区二区三| 一色屋精品视频在线观看网站| 久久亚洲私人国产精品va媚药| 久久精品国产亚洲a| 影音先锋久久精品| 亚洲国产精品成人精品| 欧美老女人xx| 午夜精彩国产免费不卡不顿大片| 亚洲性线免费观看视频成熟| 国产一级一区二区| 亚洲国产91精品在线观看| 欧美日韩成人一区二区| 午夜免费久久久久| 久久久福利视频| 日韩一级精品| 亚洲中午字幕| 最近中文字幕mv在线一区二区三区四区| 91久久香蕉国产日韩欧美9色 | 亚洲高清激情| 欧美丝袜第一区| 久久激五月天综合精品| 久久综合久久久| 9l视频自拍蝌蚪9l视频成人| 中文欧美在线视频| 在线精品视频免费观看| 99视频精品全部免费在线| 国产亚洲欧洲一区高清在线观看 | 国产精品久久久久久久久久久久久| 久久爱91午夜羞羞| 欧美国产三区| 欧美在线free| 欧美精品黄色| 久久精品视频免费| 欧美另类视频在线| 久热精品视频在线| 欧美日韩在线电影| 欧美风情在线| 国产欧美精品日韩区二区麻豆天美| 亚洲第一区色| 国产亚洲精品aa| 亚洲在线播放| 在线亚洲一区二区| 久久久久一区| 欧美一级视频精品观看| 欧美激情在线免费观看| 麻豆9191精品国产| 国产精品素人视频| 亚洲美女色禁图| 久久天天狠狠| 国产伦精品一区二区三| 欧美激情片在线观看| 国产自产2019最新不卡| 亚洲天堂黄色| 亚洲欧美日韩国产成人| 欧美日韩1区2区| 亚洲国产日韩欧美在线99| 伊人精品在线| 久久久久一区二区三区| 久久综合99re88久久爱| 国内成人自拍视频| 欧美一区二区在线免费观看| 亚洲欧美综合国产精品一区| 欧美日韩一二三区| 亚洲精品日韩精品| 日韩视频专区| 欧美日韩亚洲另类| 亚洲美女诱惑| 在线视频欧美一区| 欧美日韩一区二区三区四区五区| 亚洲人屁股眼子交8| 99在线精品观看| 欧美日韩在线第一页| 亚洲无线视频| 欧美一区二区三区播放老司机| 国产精品亚洲片夜色在线| 亚洲欧美久久| 另类国产ts人妖高潮视频| 91久久国产综合久久蜜月精品| 嫩草成人www欧美| 亚洲美女诱惑| 欧美一区二区三区在线免费观看| 国产精品一区二区久久精品| 欧美中文字幕在线播放| 欧美va亚洲va香蕉在线| 夜夜嗨av一区二区三区四季av| 国产精品va在线播放| 欧美在线在线| 亚洲欧洲中文日韩久久av乱码| 亚洲一区二区三区四区中文 | 亚洲影音先锋| 国产日韩亚洲| 女人色偷偷aa久久天堂| 99国内精品| 久久国产精品一区二区| 亚洲精品久久| 国产精品一区二区黑丝| 久久在线91| 中文欧美在线视频| 蜜臀av性久久久久蜜臀aⅴ四虎| 99精品视频免费观看视频| 国产日韩亚洲欧美精品| 欧美精品久久一区二区| 欧美在线免费看| 99精品国产福利在线观看免费 | 欧美在线播放视频| 亚洲欧洲精品一区二区三区不卡 | 欧美大片免费| 午夜久久黄色| 欧美日韩国产一区精品一区| 亚洲欧美综合| 欧美91视频| 午夜精品久久久久久久白皮肤| 韩国成人福利片在线播放| 欧美日韩国产成人在线91| 欧美中文字幕在线观看| 亚洲视频免费在线| 亚洲精品国产精品国自产观看| 久久久久久穴| 亚洲欧美中文另类| 99精品视频一区二区三区| 韩国在线视频一区| 国产精品一区一区| 欧美午夜精品久久久久久浪潮| 蜜臀av性久久久久蜜臀aⅴ| 午夜欧美大尺度福利影院在线看| 亚洲精品一区久久久久久| 欧美激情一区| 欧美成黄导航| 免费在线成人|