codeguru,codetools上找了一下,但要么就是不够详细,要么就是功能还不够强,呵呵。需要支持shift键多选和ctrl键多选,还得判断拖动是否有效

解决方案 »

  1.   

    不知道这个你满不满意:
    http://www.vckbase.com/document/viewdoc.asp?id=340
      

  2.   

    // draglist1View.cpp : implementation of the CDraglist1View class
    //#include "stdafx.h"
    #include "draglist1.h"#include "draglist1Doc.h"
    #include "draglist1View.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    //#include <shlwapi.h>
    /////////////////////////////////////////////////////////////////////////////
    // CDraglist1View
    //需要在程序类实现文件中添加AfxOleInit();IMPLEMENT_DYNCREATE(CDraglist1View, CListView)BEGIN_MESSAGE_MAP(CDraglist1View, CListView)
    //{{AFX_MSG_MAP(CDraglist1View)
    ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP
    // Standard printing commands
    ON_COMMAND(ID_FILE_PRINT, CListView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, CListView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, CListView::OnFilePrintPreview)
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CDraglist1View construction/destructionCDraglist1View::CDraglist1View()
    {
    // TODO: add construction code here}CDraglist1View::~CDraglist1View()
    {
    }BOOL CDraglist1View::PreCreateWindow(CREATESTRUCT& cs)
    {
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs return CListView::PreCreateWindow(cs);
    }/////////////////////////////////////////////////////////////////////////////
    // CDraglist1View drawingvoid CDraglist1View::OnDraw(CDC* pDC)
    {
    CDraglist1Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    }void CDraglist1View::OnInitialUpdate()
    {
    CListView::OnInitialUpdate();
        CListCtrl& listct=GetListCtrl();
        listdroptarget.Register(this);//成为拖曳操作的接收目标

    SHFILEINFO stInfo;
    HIMAGELIST hImglist;
    hImglist=(HIMAGELIST)SHGetFileInfo(_T(""),0,&stInfo,sizeof(SHFILEINFO), SHGFI_ICON|
    SHGFI_SMALLICON|SHGFI_SYSICONINDEX);

        imglist.Attach(hImglist);

        
        listct.ModifyStyle(LVS_TYPEMASK,LVS_REPORT|LVS_NOSORTHEADER|LVS_SHAREIMAGELISTS);

        listct.SetImageList(&imglist,LVSIL_SMALL);
        listct.SetExtendedStyle(LVS_EX_INFOTIP);
        
        listct.InsertColumn(0,_T("文件名"),LVCFMT_LEFT,0,0);
        listct.InsertColumn(1,_T("类型"),LVCFMT_LEFT,0,1);
        //listct.InsertColumn(2,_T("大小"),LVCFMT_LEFT,0,2);    listct.SetColumnWidth(0,LVSCW_AUTOSIZE_USEHEADER);
        listct.SetColumnWidth(1,LVSCW_AUTOSIZE_USEHEADER);
        //listct.SetColumnWidth(2,LVSCW_AUTOSIZE_USEHEADER); // TODO: You may populate your ListView with items by directly accessing
    //  its list control through a call to GetListCtrl().
    }/////////////////////////////////////////////////////////////////////////////
    // CDraglist1View printingBOOL CDraglist1View::OnPreparePrinting(CPrintInfo* pInfo)
    {
    // default preparation
    return DoPreparePrinting(pInfo);
    }void CDraglist1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    // TODO: add extra initialization before printing
    }void CDraglist1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    // TODO: add cleanup after printing
    }/////////////////////////////////////////////////////////////////////////////
    // CDraglist1View diagnostics#ifdef _DEBUG
    void CDraglist1View::AssertValid() const
    {
    CListView::AssertValid();
    }void CDraglist1View::Dump(CDumpContext& dc) const
    {
    CListView::Dump(dc);
    }CDraglist1Doc* CDraglist1View::GetDocument() // non-debug version is inline
    {
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDraglist1Doc)));
    return (CDraglist1Doc*)m_pDocument;
    }
    #endif //_DEBUG
      

  3.   

    /////////////////////////////////////////////////////////////////////////////
    // CDraglist1View message handlersvoid CDraglist1View::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
    {
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;    // TODO: Add your control notification handler code here

    *pResult = 0;    CListCtrl&     listct = GetListCtrl();
        COleDataSource listdatasrc;  //定义数据
        HGLOBAL        DropGlb; 
        DROPFILES*     pDropfiles;
        CStringList    listDraggedFiles;
        CString        listFile;
        UINT           listBuffSize=0;
        TCHAR*         listpBuff;
        FORMATETC      etc={CF_HDROP,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
        POSITION       Itempos;
        int            listSelItem;    Itempos=listct.GetFirstSelectedItemPosition();
         while (NULL!=Itempos)//取出文件名
            {
            listSelItem=listct.GetNextSelectedItem(Itempos);
            listFile=listct.GetItemText(listSelItem, 0);
            listDraggedFiles.AddTail(listFile);
            listBuffSize+=lstrlen(listFile)+1;//计算总长度,准备分配内存
            }    listBuffSize=sizeof(DROPFILES)+sizeof(TCHAR)*(listBuffSize+1);
        DropGlb=GlobalAlloc(GHND|GMEM_SHARE,listBuffSize);//在堆上分配内存    if(NULL==DropGlb)  //若句柄为空,分配失败
            return;    pDropfiles=(DROPFILES*)GlobalLock(DropGlb); //得到内存地址,准备写数据    if (NULL==pDropfiles)
            {
            GlobalFree(DropGlb);
            return;
            }    pDropfiles->pFiles=sizeof(DROPFILES);  //填充DROPFILES结构    #ifdef _UNICODE  //如果是unicode模式,设置相应标志
        pDropfiles->fWide=TRUE;
        #endif    Itempos=listDraggedFiles.GetHeadPosition(); //将所有选中文件名写进内存
        listpBuff=(TCHAR*)(LPBYTE(pDropfiles)+sizeof(DROPFILES));//得到DROPFILES结构后的内存地址
        while(NULL!=Itempos)
            {
            lstrcpy(listpBuff,(LPCTSTR)listDraggedFiles.GetNext(Itempos));
            listpBuff=1+_tcschr(listpBuff,'\0');//下一个文件名的地址
            }    GlobalUnlock(DropGlb);    listdatasrc.CacheGlobalData(CF_HDROP,DropGlb,&etc);//将数据加入数据源对象    DROPEFFECT DpEffect=listdatasrc.DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE);//允许拷贝和移动
        
        //根据结果进行相应处理,成功后由目标对象释放内存
    switch (DpEffect)
            {
            case DROPEFFECT_COPY:
            case DROPEFFECT_MOVE:
                {
                    for (listSelItem=listct.GetNextItem(-1,LVNI_SELECTED);
                      listSelItem!=-1;
                      listSelItem=listct.GetNextItem(listSelItem,LVNI_SELECTED))
                    {
                    listct.DeleteItem(listSelItem);
                    listSelItem--;
                    }            listct.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER );
                listct.SetColumnWidth(1, LVSCW_AUTOSIZE_USEHEADER );
                //listct.SetColumnWidth(2, LVSCW_AUTOSIZE_USEHEADER );
                }
            break;        case DROPEFFECT_NONE:
                {
                //在winNT/2000下,若成功,也返回DROPEFFECT_NONE,需要判断操作系统            if (0==(GetVersion()&0x80000000)) //winNT/2000下
                    {
                    bool bDeleted=false;                for (listSelItem=listct.GetNextItem(-1, LVNI_SELECTED);
                          listSelItem!=-1;
                          listSelItem=listct.GetNextItem(listSelItem,LVNI_SELECTED))
                        {
                        CString Filename=listct.GetItemText(listSelItem,0);
                        //文件已经被移出,不能找到文件和得到文件属性
                        if (0xFFFFFFFF==GetFileAttributes(Filename)&&GetLastError()==ERROR_FILE_NOT_FOUND )
                            {
                            listct.DeleteItem(listSelItem);
                            listSelItem--;
                            bDeleted=true;//从列表中移出成功
                            }
                        }
                    if (bDeleted)
                        {
                        listct.SetColumnWidth(0,LVSCW_AUTOSIZE_USEHEADER);
                        listct.SetColumnWidth(1,LVSCW_AUTOSIZE_USEHEADER);
                        //listct.SetColumnWidth(2,LVSCW_AUTOSIZE_USEHEADER);
                        }
                    else
                        {//winNT/2000下失败,释放内存
                        GlobalFree(DropGlb);
                        }
                    } 
                else
                    {//win95/98下失败,释放内存
                    GlobalFree(DropGlb);
                    }
                }
            break;  
            }  }
      

  4.   

    DROPEFFECT CDraglist1View::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
    {
    // TODO: Add your specialized code here and/or call the base class
    DROPEFFECT dpEffect = DROPEFFECT_NONE;//初始返回值
        //检查有无数据
        if (NULL!=pDataObject->GetGlobalData(CF_HDROP))
    {
    //if(0==(GetVersion()&0x80000000))//检查操作系统版本,是否为winNT/2000
            //dpEffect=DROPEFFECT_COPY;
    //else
    dpEffect=DROPEFFECT_COPY;
    }
           
        return dpEffect;
    }void CDraglist1View::OnDragLeave() 
    {
    // TODO: Add your specialized code here and/or call the base class
    CListView::OnDragLeave();
    }DROPEFFECT CDraglist1View::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
    {
    // TODO: Add your specialized code here and/or call the base class

    DROPEFFECT dpEffect=DROPEFFECT_NONE;
        if (NULL!=pDataObject->GetGlobalData(CF_HDROP))
                dpEffect=DROPEFFECT_COPY;
        return dpEffect;
    }BOOL CDraglist1View::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) 
    {
    HGLOBAL     Dropglb2;
        HDROP       hdp;
        UINT        Filesnum;
        TCHAR       FileNext[MAX_PATH];
        SHFILEINFO  stFileInfo;
        LVFINDINFO  stlvFindInfo={LVFI_STRING,FileNext};
        LVITEM      stlvItem;
        CListCtrl&  listct=GetListCtrl();
        int         Index=listct.GetItemCount();
        //HANDLE      hFind;
        //WIN32_FIND_DATA stwinFind;
        //TCHAR       FileLen[64];

        //读数据

        Dropglb2=pDataObject->GetGlobalData(CF_HDROP);//得到内存句柄
        
        if (NULL==Dropglb2)
    {
            return FALSE;
    }

        hdp=(HDROP)GlobalLock(Dropglb2); //得到内存地址

        if (NULL==hdp)
    {
            GlobalUnlock(Dropglb2);
            return FALSE;
    }

        Filesnum=DragQueryFile(hdp,-1,NULL,0);//得到文件数

        for (UINT Fileitem=0;Fileitem<Filesnum;Fileitem++)
    {
    if (DragQueryFile(hdp,Fileitem,FileNext,MAX_PATH)>0)
    {
    if (-1!=listct.FindItem(&stlvFindInfo,-1))//文件名存在则跳过
                    continue;

                SHGetFileInfo(FileNext,0,&stFileInfo,sizeof(stFileInfo),SHGFI_ATTRIBUTES|SHGFI_TYPENAME|SHGFI_SYSICONINDEX);

                ZeroMemory(&stlvItem, sizeof(LVITEM));//内存清零

                stlvItem.mask   =LVIF_TEXT|LVIF_IMAGE;//填充LVITEM结构
                stlvItem.iItem  =Index;
                stlvItem.pszText=FileNext;
                stlvItem.iImage =stFileInfo.iIcon;

    if (stFileInfo.dwAttributes&SFGAO_GHOSTED)
    {
                    stlvItem.mask|=LVIF_STATE;
                    stlvItem.state=stlvItem.stateMask=LVIS_CUT;
    }

                listct.InsertItem(&stlvItem); //插入列表项,填充第一列

                listct.SetItemText(Index,1,stFileInfo.szTypeName);//填充第二列

                //hFind=FindFirstFile(FileNext,&stwinFind);

                //if (INVALID_HANDLE_VALUE!=hFind)
    // {
    // StrFormatByteSize(stwinFind.nFileSizeLow,FileLen,64);
    // FindClose(hFind);
    // }

                //listct.SetItemText(Index,2,FileLen);//填充第三列

                Index++;
    }
    }

        listct.SetColumnWidth(0,LVSCW_AUTOSIZE_USEHEADER);//调整列宽
        listct.SetColumnWidth(1,LVSCW_AUTOSIZE_USEHEADER);
        //listct.SetColumnWidth(2,LVSCW_AUTOSIZE_USEHEADER);

        listct.EnsureVisible(Index-1,FALSE);//根据需要添加滚动条 GlobalUnlock(Dropglb2);
    GlobalFree(Dropglb2);//释放内存    return TRUE;}
    void CDraglist1View::OnDestroy() 
    {
        if (NULL!=imglist.GetSafeHandle())
            imglist.Detach();
    CListView::OnDestroy();
    // TODO: Add your message handler code here
    }
      

  5.   

    谢谢各位,还有就是拖动的时候插入的位置能自己指定么?比如我把第2个节点拖到第一个节点前面,也就是想让第2个节点和第1个节点位置互换可以么,好像insertitem的时候只有TVI_FIRST, TVI_LAST, or TVI_SORT?