• <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>
            Dict.CN 在線詞典, 英語(yǔ)學(xué)習(xí), 在線翻譯

            學(xué)海苦作舟,書(shū)山勤為徑

            留下點(diǎn)回憶

            常用鏈接

            統(tǒng)計(jì)

            積分與排名

            Denoise

            English study

            Web技術(shù)

            數(shù)據(jù)壓縮

            一些連接

            最新評(píng)論

            第五部分:Drop源(OLE drag&drop之旅)

            歡迎來(lái)到OLE拖放旅程系列的第五部分,我們機(jī)會(huì)到了OLE拖放實(shí)現(xiàn)的最后階段,現(xiàn)在需要做的事情就是實(shí)現(xiàn)IDropSourceIDropTarget接口;一般我們完成這些,我們就可以在任何程序中添加拖放操作了。

            本部分的目的在于實(shí)現(xiàn)一個(gè)用作拖放源的簡(jiǎn)單程序,它不能接收任何拖放的數(shù)據(jù),但這不要緊,因?yàn)槲覀兡苁褂萌魏纹匠VС滞戏挪僮鞯?/SPAN>windows程序(例如:WordPad)來(lái)測(cè)試,程序就是一個(gè)windowsEdit控件,它是子類化的,且支持拖操作。

            這個(gè)子類的細(xì)節(jié)在這里不討論,但源碼可以很清晰的說(shuō)明這個(gè)任務(wù)。

            成為一個(gè)拖放的源對(duì)象

            初始化一個(gè)拖放操作很簡(jiǎn)單,只要調(diào)用DoDragDrop這個(gè)API就足夠了。

            WINOLEAPI DoDragDrop (
               IDataObject * pDataObject,   // Pointer to the data object
               IDropSource * pDropSource,   // Pointer to the source
               DWORD          dwOKEffect,    // Effects allowed by the source
               DWORD        * pdwEffect      // Pointer to effects on the source
               );

            一旦你調(diào)用這個(gè)AIPOLE運(yùn)行時(shí)就代表你的程序來(lái)接管并處理所有必要的鼠標(biāo)和鍵盤windows消息,因此你基本上將控制權(quán)在調(diào)用這個(gè)函數(shù)的時(shí)候交給了OLE

            前兩個(gè)參數(shù)是COM接口,一個(gè)是IDataObject-我們前面已經(jīng)介紹了這個(gè)接口。

            第三個(gè)參數(shù)是一個(gè)DWORD值,它表示源允許的拖動(dòng)效果,其以位掩碼的方式給出。這些效果是DROPEFFECT_XXX值,通常是DROPEFFECT_MOVEDROPEFFECT_COPY的聯(lián)合。如果你想僅僅允許從我們的源復(fù)制數(shù)據(jù),那么我們應(yīng)該就指定DROPEFFECT_COPY

            最后一個(gè)參數(shù)是指向DWORD的指針。該值在DoDragDrop返回的時(shí)候可以訪問(wèn),包含OLE期望源對(duì)象執(zhí)行的效果和動(dòng)作,例如:用戶選擇移動(dòng)還是復(fù)制數(shù)據(jù)?

            執(zhí)行拖放操作的代碼實(shí)際上分成三步:首先我們需要寫(xiě)一個(gè)小的功能函數(shù)叫做StringToHandle,它轉(zhuǎn)換一個(gè)char*字符為HGLOBAL,從而我們可以在OLE中使用:

            HANDLE StringToHandle (char *szText, int nTextLen)
            {
                void  *ptr;
                // if text length is -1 then treat as a nul-terminated string
                if(nTextLen == -1)
                    nTextLen = lstrlen (szText) + 1;
                // allocate and lock a global memory buffer. Make it fixed
                // data so we don't have to use GlobalLock
                ptr = (void *)GlobalAlloc(GMEM_FIXED, nTextLen);
                // copy the string into the buffer
                memcpy (ptr, szText, nTextLen);
                return ptr;
            }

            StringToHandle完全不執(zhí)行錯(cuò)誤簡(jiǎn)單,因此這是你的責(zé)任;下一步是準(zhǔn)備拖放操作使用的數(shù)據(jù):

            FORMATETC fmtetc = 
            { 
                CF_TEXT,            // we will be dropping some text
                0, 
                DVASPECT_CONTENT, 
                -1, 
                TYMED_HGLOBAL       // stored as a HGLOBAL
            };
            STGMEDIUM stgmed = 
            { 
                TYMED_HGLOBAL, 
                {0}, 
                0 
            };
            // Create a HGLOBAL inside the storage medium
            stgmed.hGlobal = StringToHandle ("Hello, World", -1);

            緊接著就是創(chuàng)建兩個(gè)拖放操作的COM接口:IDropSourceIDataObject。我們?cè)谇懊娴穆贸讨袑?shí)現(xiàn)了CreateDataObject,馬上會(huì)實(shí)現(xiàn)CreateDropSource

            IDropSource *pDropSource;
            IDataObject *pDataObject;
             
            CreateDropSource (&pDropSource);
            CreateDataObject (&pDataObject, &fmtetc, &stgmed, 1);

            在創(chuàng)建好IDataObjectIDropSource之后就可以調(diào)用DoDragDrop了:

            DWORD dwResult;
            // do the drag-drop!
            dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY, &dwEffect);
            // finished. Check the return values to see if we need to do anything else
            if(dwResult == DRAGDROP_S_DROP)
            {
                if(dwEffect == DROPEFFECT_MOVE)
                {
                    // remove the data we just dropped from active document
                }
            }

            最后一件事情就是清除所有我們使用過(guò)的資源,首先刪除我們使用的兩個(gè)COM接口,然后刪除包含我們文本的HGLOBAL內(nèi)存緩沖區(qū)。

            // release the COM interfaces
            pDropSource->Release();
            pDataObject->Release();
            ReleaseStgMedium(&stgmed);

            什么時(shí)候調(diào)用DoDragDrop方法來(lái)

            知道了怎么樣初始化拖放操作非常好,但真正重要的是理解將上面的代碼放到你程序的什么位置?

            因?yàn)橥戏挪僮魇腔谑髽?biāo)的,它通常在處理windows鼠標(biāo)消息的時(shí)候被初始化,如果你在支持拖放操作的程序中測(cè)試(例如WordPad),你會(huì)觀察到RichEdit控件有下面的行為:

            1.         當(dāng)鼠標(biāo)移動(dòng)過(guò)選中的文本,它的光標(biāo)形狀變成箭頭

            2.         當(dāng)按下左鍵的時(shí)候,被選擇的不會(huì)被刪除,且設(shè)置內(nèi)部狀態(tài)來(lái)指示可能要開(kāi)始拖放操作

            3.         當(dāng)鼠標(biāo)被第一次移動(dòng)(并且內(nèi)部狀態(tài)指示左鍵一直按在被選中的文本區(qū)域中),拖動(dòng)操作開(kāi)始。

            4.         在這個(gè)時(shí)候,OLE接管并處理所有鼠標(biāo)消息,直到操作完成

            5.         然而,如果左鍵被釋放了,或者鼠標(biāo)根本沒(méi)有移動(dòng),RichEdit選擇部分被清除。

            這些行為在CC++中實(shí)現(xiàn)非常簡(jiǎn)單,對(duì)于我們的子類化的控件,可能是這樣:

             

             

             

             

            case WM_LBUTTONDOWN:
                if(MouseInSelection(hwndEdit))
                {
                    fMouseDown = TRUE;
                    return 0;
                }
                break;
             
            case WM_MOUSEMOUVE:
                if(fMouseDown == TRUE)
                {
                    DoDragDrop (...);
                }
                fMouseDown = FALSE;
                break;
             
            case WM_LBUTTONUP:
                fMouseDown = FALSE;
                break;

            IDropSource接口

            IDropSource是拖放操作中最簡(jiǎn)單的接口,除了IUnknown函數(shù)外,它僅僅包含兩個(gè)需要實(shí)現(xiàn)的函數(shù):

            IDropSource 方法

            描述

            QueryContinueDrag

            決定是否應(yīng)該繼續(xù)、取消或完成一個(gè)拖放操作,基于鼠標(biāo)和<Escape> <Control> <Shift> 鍵的狀態(tài)。

            GiveFeedback

            為拖放操作的源提供一個(gè)用來(lái)給出可視化效果的方法,基于鼠標(biāo)鍵、escapecontrol等鍵的狀態(tài)。

            兩個(gè)函數(shù)由COM/OLE運(yùn)行時(shí)在拖放操作的修飾鍵狀態(tài)改變的時(shí)候調(diào)用,需要做的工作就是實(shí)現(xiàn)這個(gè)接口-實(shí)際上,在準(zhǔn)備拖放的時(shí)候已經(jīng)做了很多編碼了。

            實(shí)現(xiàn)IDropSource

            同樣我們用一個(gè)源文件來(lái)實(shí)現(xiàn)drop源。在dropsource.cpp中是類的定義,下面就是這些代碼:

             

             

            class CDropSource : public IDropSource
            {
            public:
                //
                // IUnknown members
                //
                HRESULT __stdcall QueryInterface    (REFIID iid, void ** ppvObject);
                ULONG   __stdcall AddRef            (void);
                ULONG   __stdcall Release           (void);
                //
                // IDropSource members
                //
                HRESULT __stdcall QueryContinueDrag (BOOL fEscapePressed, DWORD grfKeyState);
                HRESULT __stdcall GiveFeedback      (DWORD dwEffect);
                //
                // Constructor / Destructor
                //
                CDropSource();
                ~CDropSource();
            private:
                //
                // private members and functions
                //
                LONG    m_lRefCount;
            };

            該類的構(gòu)造函數(shù)除了執(zhí)行初始化對(duì)象引用記數(shù)的操作外不執(zhí)行任何其他的工作。

            IDropSource::QueryContinueDrag

            下面是QueryContinueDrag函數(shù)的定義:

            HRESULT QueryContinueDrag(
               BOOL   fEscapePressed,        // Is the <Escape> key being pressed?
               DWORD  grfKeyState,           // Current state of keyboard modifier keys
               );

            函數(shù)返回三個(gè)值的一個(gè):

            1.       S_OK,拖動(dòng)操作應(yīng)該繼續(xù);如果沒(méi)有檢查到錯(cuò)誤就是這個(gè)結(jié)果,開(kāi)始拖放操作的鼠標(biāo)沒(méi)有被釋放,也沒(méi)有ESC

            2.       DRAGDROP_S_DROP,放操作發(fā)生來(lái)完成拖操作;如果grfKeyState指出啟動(dòng)拖放操作的鍵松開(kāi)了就會(huì)發(fā)生這個(gè)結(jié)果。

            3.       DRAGDROP_S_CANCEL;沒(méi)有放操作發(fā)生時(shí)拖操作被放棄,這是fEscapePressed是真的表示ESC鍵被按下的結(jié)果。

            作為COM的習(xí)慣,下面的兩個(gè)行為在拖放操作中應(yīng)該遵守:

            1.  按下Escape鍵時(shí)取消拖放操作

            2.  松開(kāi)鼠標(biāo)左鍵的時(shí)候,應(yīng)該執(zhí)行放操作

            為了符合這些規(guī)則,QueryContinueDrag如下實(shí)現(xiàn):

            HRESULT __stdcall CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
            {
                // if the Escape key has been pressed since the last call, cancel the drop
                if(fEscapePressed == TRUE)
                    return DRAGDROP_S_CANCEL;       
                // if the LeftMouse button has been released, then do the drop!
                if((grfKeyState & MK_LBUTTON) == 0)
                    return DRAGDROP_S_DROP;
                // continue with the drag-drop
                return S_OK;
            }

            IDropSource::GiveFeedback

            這個(gè)函數(shù)通常在每個(gè)程序中都不同,因?yàn)闆](méi)有一個(gè)程序是相同的。然而除非我們提供一個(gè)圖形反饋效果,否則我們的是很簡(jiǎn)單:

            HRESULT __stdcall CDropSource::GiveFeedback (DWORD dwEffect)
            {
                return DRAGDROP_S_USEDEFAULTCURSORS;
            }

            參數(shù)dwEffect(它告訴我們哪個(gè)鼠標(biāo)鍵被按下,哪個(gè)鍵盤修飾在使用)在許多拖放操作程序中都可以忽略,簡(jiǎn)單的DRAGDROP_S_USEDEFAULTCURSORS來(lái)告訴COM在發(fā)生任何修飾符改變的時(shí)候更新鼠標(biāo)光標(biāo)。

            當(dāng)然,我們可以檢查dwEffectDROPEFFECT_XXX標(biāo)志來(lái)PAINT我們的源窗口并返回S_OK,但為什么要這么麻煩來(lái)?

            posted on 2006-03-06 08:49 笨笨 閱讀(4772) 評(píng)論(3)  編輯 收藏 引用 所屬分類: OLE Drag&Drop

            評(píng)論

            # re: 第五部分:Drop源(OLE drag&drop之旅) 2006-08-17 16:34 來(lái)自CSDN的thesuper

            看來(lái)看去,沒(méi)看到!!  回復(fù)  更多評(píng)論   

            # re: 第五部分:Drop源(OLE drag&drop之旅) 2006-12-11 15:34 waiting4you(毛毛)

            簡(jiǎn)單易懂,謝謝樓主無(wú)私奉獻(xiàn)和辛苦翻譯  回復(fù)  更多評(píng)論   

            # re: 第五部分:Drop源(OLE drag&drop之旅) [未登錄](méi) 2012-02-14 12:21 chunyou128

            lz厲害!膜拜  回復(fù)  更多評(píng)論   

            久久国产精品-国产精品| 天天影视色香欲综合久久| 久久久久久久女国产乱让韩 | 91久久香蕉国产熟女线看| 色综合久久88色综合天天| 久久久久久国产精品美女| 久久精品国产清自在天天线| 久久久无码人妻精品无码| 久久久WWW成人免费毛片| 伊人久久大香线蕉av一区| 国产91久久综合| 国产亚洲精品美女久久久| 久久久久亚洲国产| 久久免费观看视频| 久久综合狠狠综合久久激情 | 亚洲精品国产综合久久一线| 久久黄色视频| 久久AV高清无码| 伊人久久综合成人网| 久久99精品久久久久久水蜜桃| 亚洲成色999久久网站| 中文字幕热久久久久久久| 色综合合久久天天给综看| 午夜不卡888久久| 国产精品一区二区久久| 免费久久人人爽人人爽av| 思思久久99热只有频精品66| 51久久夜色精品国产| 国产精品久久久久9999| 精品精品国产自在久久高清 | 色偷偷久久一区二区三区| 狼狼综合久久久久综合网| 久久精品中文字幕大胸| 精品久久久久久久中文字幕| 99久久无色码中文字幕| 69SEX久久精品国产麻豆| 亚洲精品乱码久久久久久蜜桃不卡 | 精品水蜜桃久久久久久久| 国产精品久久久久久久午夜片| 色综合久久最新中文字幕| 久久最新精品国产|