实现拖出,现在程序的数据源是Listview,具体的内容根据Listview选中的文件从ftp下载(这个无所谓,反正从其他地方来的,数据库的stream等等都可以,不同于普通文本拖放),希望拖放完毕,鼠标放开以后开始下载ftp的内容,并保存到本地,(从程序窗口中的listview拖到桌面等地方)不想用控件,主要想知道原理,如果哪位兄弟帮我把代码从控件中分离出来夜行,非常感谢

解决方案 »

  1.   

    http://community.csdn.net/Expert/topic/5319/5319586.xml?temp=6.657046E-02
      

  2.   

    拖放要放在OLE对象里涉及到的API
    DoDragDropDoDragDrop需要用到IDataObject,IDropSource
    这个DELPHI没有申明需要自己做,过程要根据需要自己写了
    关键过程为
    GetData 向目标窗口传送数据
    QueryGetData 目标窗口查询数据接口类型
    其他可以直接Result := E_NOTIMPL;表示为接口不支持
    还有个SetData接口,这个是将OLE数据存入IDataObject类,因为过程是自己写的,可以直接使用程序中的公共变量数据,不用通过SetData将数据写入IDataObject类uses ShlObj,ActiveX,  ComObj;
     Tform1 = class(TForm, IDropSource)
      ....
      ....
     Pubilc
        //IDropSource
        function QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: Longint): HResult; stdcall;
        function GiveFeedback(dwEffect: Longint): HResult; stdcall;
     end;  TDataObject = class(TInterfacedObject,IDataObject)
      public
        constructor Create;
        procedure Free;    function GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult; stdcall;
        function GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium): HResult; stdcall;
        function QueryGetData(const formatetc: TFormatEtc): HResult; stdcall;
        function GetCanonicalFormatEtc(const formatetc: TFormatEtc; out formatetcOut: TFormatEtc): HResult;stdcall;
        function SetData(const formatetc: TFormatEtc; var medium: TStgMedium; fRelease: BOOL): HResult; stdcall;
        function EnumFormatEtc(dwDirection: Longint; out enumFormatEtc: IEnumFormatEtc): HResult; stdcall;
        function DAdvise(const formatetc: TFormatEtc; advf: Longint; const advSink: IAdviseSink; out dwConnection: Longint): HResult; stdcall;
        function DUnadvise(dwConnection: Longint): HResult; stdcall;
        function EnumDAdvise(out enumAdvise: IEnumStatData): HResult; stdcall;
      end;function Tform1.QueryContinueDrag(fEscapePressed: BOOL;
      grfKeyState: Longint): HResult; stdcall;
    begin
      if fEscapePressed or (grfKeyState and MK_RBUTTON = MK_RBUTTON) then
         Result := DRAGDROP_S_CANCEL
      else
         Result := DRAGDROP_S_DROP;
    end;
    function Tform1.GiveFeedback(dwEffect: Longint): HResult; stdcall;
    begin
      Result := DRAGDROP_S_USEDEFAULTCURSORS;
    end;//QueryGetData过程
    function TDataObject.QueryGetData(const formatetc: TFormatEtc): HResult; stdcall;
    begin
     Result := DV_E_FORMATETC; //不支持的格式 if (formatetc.cfFormat=CF_HDROP) and  //表示支持文件拖拽格式
          (formatetc.tymed=TYMED_HGLOBAL   ) and
          (formatetc.dwAspect=DVASPECT_CONTENT) then
         Result := S_OK;
    end;//GetData过程
    function TDataObject.GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult; stdcall;
    var
    BufferText : String;
    pGlobal    : Pointer;
    begin
     Result := DV_E_FORMATETC; //不支持的格式
     if not (Self.QueryGetData(formatetcIn)=S_OK) then exit;
       FillChar(Medium,Sizeof(TStgMedium),0);
       Medium.tymed:=formatetcIn.tymed;
    BufferText:='c:\temp\aa.txt'+#0+#0;  
    //需要拖拽的文件,多个的如下
    //'c:\temp\aa.txt'+#0+#0+'c:\temp\aa.txt'+#0+#0;+'c:\temp\aa.txt'+#0+#0;
             Medium.hGlobal := GlobalAlloc(GMEM_ZEROINIT or GMEM_MOVEABLE or  GMEM_SHARE, Length(BufferText)+1+Sizeof(TDropFiles));
             pGlobal := GlobalLock(Medium.hGlobal);
             PDropFiles(pGlobal)^.pFiles:=Sizeof(TDropFiles);
             PDropFiles(pGlobal)^.pt:=Point(0,0);
             PDropFiles(pGlobal)^.fNC:=False;
             PDropFiles(pGlobal)^.fWide:=False;
             inc(Longword(pGlobal),Sizeof(TDropFiles)); //指针后移
             CopyMemory(PGlobal,Pchar(BufferText),Length(BufferText)+1);
             GlobalUnlock(Medium.hGlobal);
             Medium.unkForRelease := nil;
    Result := S_OK;
    end;
    //////////////
    在需要拖拽的时候
    var
    DataObject : TDataObject;
    begin
    DataObject:=TDataObject.Create;
    Effect := DROPEFFECT_NONE;
    try
       DoDragDrop(DataObject, Self, DROPEFFECT_MOVE, Effect);
    except
    end; 
    DataObject.Free;
    end;
      

  3.   

    事实上你拖拽的时候是先已经选定好了的,比如从A拖到B里面,B里面显示的只是A里面选中的东西(桌面也是一个文件夹),而实际上是开了线程开始下载(处理)的
      

  4.   

    谢谢楼上两位兄弟,dabaicai(小老头) 思路可以考虑,不知道算不算“正统”的做法谢谢to SonicX(SonicX),现在的问题是文件其实并不存在本地楼下继续
      

  5.   

    根据MSDN说法就是先将文件存到硬盘上再进行拖拽,拖拽文件没有内存操作方式
    你可以看下其他软件的拖拽,都是将文件先存到TEMP目录的,比如WINRAR,FOXMAIL...
      

  6.   

    是的,不过会有个小问题,就是如果网络不是很好,我们在DoDragDrop前准备数据这个过程会很漫长,这样不太好
      

  7.   

    转变下思路吧
    在GetData过程做点改动,比如弄个文件进度条什么的,后台下载数据咯
      

  8.   

    看来一个简单的办法就是先建立一个很小的同名临时文件,鼠标放开以后在真正开始下载,并填充文件。msdn的例子是间建立临时文件,不知道有没有机制可以在DoDragDrop只有调用我们的方法来处理数据获取。比如类型为TYPED_ISTREAM等等,一直没有好的资料和示例