关于MFC中任意对象的拖拽功能的实现(COleDataSource, COleDropTarget)


    拖拽功能的实现是一个全局的功能实现,也就是没有进程之隔,是一个类似windows的文件拖拽管理和打开的功能。而下面说记录的是关于任意内容的全局拖拽的实现细节。关于相关函数和对象的具体描述可以直接MSDN查看,这里就不对其进行详细的简介。


    大体的实现可以分为两个主要的部分:

         1. 被拖拽对象中添加COleDataSource,以处理被拖拽对象

         2. 在拖拽目标中添加COleDropTarget, 以处理拖拽目标接受拖拽的相关事件


    下面是具体的代码示例,这个示例的具体功能实现的是把CTreeCtrl中的一个item所关联的数据拖拽到指定的CView类中,类似与文件的拖拽打开。


     1. 关于被拖拽对象CTreeCtrl中的相关代码实现:

            1.1.  首先在CTreeCtrl的扩展类中添加COleDataSource对象,我这里添加的是COleDataSource类型的指针。

扫描二维码关注公众号,回复: 2429757 查看本文章

class CDataViewTree : public CTreeCtrl

{

 private:

    COleDataSource* m_dropSource;

    ... ...

    //这是开始拖拽的消息处理函数

public:
    afx_msg void OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult);

    ... ...

};

           

            1.2. 在消息映射表中添加消息映射,处理开始拖拽的消息。

                     BEGIN_MESSAGE_MAP(CDataViewTree, CTreeCtrl)
                              ON_NOTIFY_REFLECT(TVN_BEGINDRAG, &CDataViewTree::OnTvnBegindrag)
                     END_MESSAGE_MAP()


            1.3. 具体的实现部分都在OnTvnBegingdrag()函数中。

void CDataViewTree::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)

{
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    *pResult = 0;

    char* hgMem = NULL, *htmpMem = NULL;

    HTREEITEM hItem = GetSelectedItem();

    CString dataBuf_dataName, dataBuf_dataID;
    int typeIndex, ctrlType, bufSize;
    //可以修改成多项同时拖拽
    if (hItem != NULL && GetChildItem(hItem) == NULL)
    {
         //这里我的每个item关联的是一个变量,所用数据包括了变量的名字,ID, 类型
        dataBuf_dataName = GetItemText(hItem);
        dataBuf_dataID = GetItemID(hItem);
        typeIndex     = GetItemTypeIndex(hItem);

        bufSize = 4 + 32*2 + dataBuf_dataName.GetLength()*2+2;

        m_dropSource = new COleDataSource;

        //开辟全局缓存,用来保存被拖放对象的相关数据,这里一个大小
        hgMem = (char*)GlobalAlloc(GPTR, bufSize);

        htmpMem = (char*)GlobalLock((HGLOBAL)hgMem);
        ASSERT(htmpMem != NULL);

        ZeroMemory(htmpMem, bufSize);

        // 缓存中数据的保存格式可以根据自己的需求来定,注意要便于缓存的读取
        *((int*)htmpMem) = typeIndex;
        lstrcpy((TCHAR*)(htmpMem + 4), dataBuf_dataID);
        lstrcpy((TCHAR*)(htmpMem + 68), dataBuf_dataName);

        // 缓存关联
        m_dropSource->Empty();
        m_dropSource->CacheGlobalData(CF_TEXT, (HGLOBAL)htmpMem);

        // 开始数据拖拽,函数会在拖拽结束后返回
        DROPEFFECT dropEffect = m_dropSource->DoDragDrop();

        // 空间的解锁和释放
        GlobalUnlock((HGLOBAL)hgMem);

        GlobalFree((HGLOBAL)hgMem);
        delete m_dropSource;
        m_dropSource = NULL;
    }
}


     2. 关于拖拽目标中的相关代码实现

         2.1. 拖拽接收目标中添加COleDropTarget对象。并添加相关的处理函数,其中包括了OnDragEnter(), OnDragOver(), OnDragLeave(), 和OnDrop()函数,这几个函数都是虚函数,你可以使用MFC类向导添加,也可以自己手动添加。

class CWindowView : public CView
 {

    private:

        COleDropTarget m_oleTarget;

         ... ...

    public:

         virtual DROPEFFECT OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
         virtual void OnDragLeave();
         virtual DROPEFFECT OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
         virtual BOOL OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);

         ... ...

}


        2.2. 在创建CView时,一定要调用COleDropTarget对象的Register()方法,注册该窗口,使窗口可以接受拖拽。

int CWindowView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;

    // 注册,
    m_oleTarget.Register(this);


    return 0;
}


       2.3. 相关的虚函数的具体实现

DROPEFFECT CWindowView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
    // 返回值可能决定图标显示效果
    return DROPEFFECT_MOVE;
}


void CGeneralUI_CreateWindowView::OnDragLeave()
{
    CView::OnDragLeave();
}


DROPEFFECT CGeneralUI_CreateWindowView::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
    return DROPEFFECT_MOVE;
}


BOOL CGeneralUI_CreateWindowView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
    // TODO: 在此添加专用代码和/或调用基类

    HGLOBAL hgMem = NULL;
    char* htmpMem = NULL;

    CString dataBuf_dataName, dataBuf_dataID;
    int typeIndex= 6;

    if (pDataObject->IsDataAvailable(CF_TEXT))
    {
        hgMem = pDataObject->GetGlobalData(CF_TEXT);

        htmpMem = (char*)GlobalLock(hgMem);

        if (htmpMem != NULL)
        {
            typeIndex = *(int*)htmpMem;
            dataBuf_dataID.Format(L"%s", (TCHAR*)(htmpMem + 4));
            dataBuf_dataName.Format(L"%s", (TCHAR*)(htmpMem + 68));

            CWnd* onCtrlPtr = CheckCurSelCtrl(point);

            // 获取到了数据,根据自己的要求做你自己的相关操作

           AfxMessageBox(dataBuf_dataName + L" " + dataBuf_dataID);

        }
    }

    GlobalUnlock(hgMem);

    return TRUE;
}      


以上就是拖拽功能实现的全部代码,希望可以帮到大家。代码的优化还请大家多给点意见。


关于参考资料我就不进行罗列了。


猜你喜欢

转载自blog.csdn.net/wasaiheihei/article/details/41440647