【问题标题】:How do you drag and drop a file from Explorer Shell into a VirtualTreeView control in a Delphi application?如何将文件从 Explorer Shell 拖放到 Delphi 应用程序中的 VirtualTreeView 控件中?
【发布时间】:2010-09-22 14:12:30
【问题描述】:

Mike Lischke 在 VirtualTreeView 中提供了广泛的拖放支持,我正在使用 TVirtualStringTree,它有一些拖放事件,但我不知道如何让它接受外壳拖放 -并将一些文件从 Windows 资源管理器外壳拖放到我的应用程序中。我想加载文件,当它们被拖到放置控件上时。

我尝试使用来自 Anders Melander 的第三方代码集来处理拖放,但由于 VirtualTreeView 已经将自己注册为放置目标,我无法使用它。

编辑:我找到了一个简单的解决方法:在 VT.TreeOptions.MiscOptions 中关闭 toAcceptOLEDrop。 如果有人知道在不使用第三方 OLE-shell-drag-drop 库并使用其广泛的 OLE 拖放支持来提取从 Shell 中拖入的文件名列表的情况下使用 VirtualTreeView 的方法,那将是很酷的。

【问题讨论】:

    标签: delphi drag-and-drop windows-shell virtualtreeview


    【解决方案1】:

    我的实现(与 Delphi 2010 配合得很好。必须添加 ActiveX、ShellApi 才能使用编译):

    procedure TfMain.vstTreeDragDrop(Sender: TBaseVirtualTree; Source: TObject;
      DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState;
      Pt: TPoint; var Effect: Integer; Mode: TDropMode);
    var
      I, j: Integer;
      MyList: TStringList;
      AttachMode: TVTNodeAttachMode;
    begin
      if Mode = dmOnNode then
        AttachMode := amInsertBefore
      else if Mode = dmAbove then
        AttachMode := amInsertBefore
      else if Mode = dmBelow then
        AttachMode := amInsertAfter
      else
        AttachMode := amAddChildLast;
    
      MyList := TStringList.Create;
      try
        for i := 0 to High(formats) - 1 do
        begin
          if (Formats[i] = CF_HDROP) then
          begin
            GetFileListFromObj(DataObject, MyList);
    
            //here we have all filenames
            for j:=0 to MyList.Count - 1 do
            begin
              Sender.InsertNode(Sender.DropTargetNode, AttachMode);
            end; 
          end;  
        end;
      finally
        MyList.Free;
      end;
    end;
    
    procedure TfMain.GetFileListFromObj(const DataObj: IDataObject;
      FileList: TStringList);
    var
      FmtEtc: TFormatEtc;                   // specifies required data format
      Medium: TStgMedium;                   // storage medium containing file list
      DroppedFileCount: Integer;            // number of dropped files
      I: Integer;                           // loops thru dropped files
      FileNameLength: Integer;              // length of a dropped file name
      FileName: string;                 // name of a dropped file
    begin
      // Get required storage medium from data object
      FmtEtc.cfFormat := CF_HDROP;
      FmtEtc.ptd := nil;
      FmtEtc.dwAspect := DVASPECT_CONTENT;
      FmtEtc.lindex := -1;
      FmtEtc.tymed := TYMED_HGLOBAL;
      OleCheck(DataObj.GetData(FmtEtc, Medium));
      try
        try
          // Get count of files dropped
          DroppedFileCount := DragQueryFile(
            Medium.hGlobal, $FFFFFFFF, nil, 0
            );
          // Get name of each file dropped and process it
          for I := 0 to Pred(DroppedFileCount) do
            begin
              // get length of file name, then name itself
              FileNameLength := DragQueryFile(Medium.hGlobal, I, nil, 0);
              SetLength(FileName, FileNameLength);
              DragQueryFileW(
                Medium.hGlobal, I, PWideChar(FileName), FileNameLength + 1
                );
              // add file name to list
              FileList.Append(FileName);
            end;
        finally
          // Tidy up - release the drop handle
          // don't use DropH again after this
          DragFinish(Medium.hGlobal);
        end;
      finally
        ReleaseStgMedium(Medium);
      end;
    
    end;
    

    【讨论】:

      【解决方案2】:

      我使用这种方法来捕获(接收)从资源管理器拖入 TWinControl 的文件。
      您可以在您的控件上对其进行测试。在标准的 TTreeView 中工作正常。

      将 ShellAPI 添加到使用中。

      在私人部分:

        private
          originalEditWindowProc : TWndMethod;
          procedure EditWindowProc(var Msg:TMessage);
          // accept the files dropped
          procedure FilesDrop(var Msg: TWMDROPFILES);
      

      在您的表单的 OnCreate 处:

        // Assign procedures
        originalEditWindowProc := TreeView1.WindowProc;
        TreeView1.WindowProc := EditWindowProc;
        // Aceptar ficheros arrastrados  // Accept the files
        ShellAPI.DragAcceptFiles(TreeView1.Handle, True);
      

      这两个过程是这样的:

      // Al arrastrar ficheros sobre el TV.  On drop files to TV
      procedure TForm1.FilesDrop(var Msg: TWMDROPFILES);
      var
        i:Integer;
        DroppedFilename:string;
        numFiles : longInt;
        buffer : array[0..MAX_PATH] of char;
      begin
        // Número de ficheros arrastrados // Number of files
        numFiles := DragQueryFile(Msg.Drop, $FFFFFFFF, nil, 0) ;
      
        // Recorrido por todos los arrastrados // Accept all files
        for i := 0 to (numFiles - 1) do begin
      
          DragQueryFile(Msg.Drop, i, @buffer, sizeof(buffer));
      
          // Proteccion
          try
            DroppedFilename := buffer;
      
            // HERE you can do something with the file...
            TreeView1.Items.AddChild(nil, DroppedFilename);
          except
            on E:Exception do begin
              // catch
            end;
          end;
        end;
      end;
      
      
      procedure TForm1.EditWindowProc(var Msg: TMessage);
      begin
        // if correct message, execute the procedure
        if Msg.Msg = WM_DROPFILES then begin
          FilesDrop(TWMDROPFILES(Msg))
        end
        else begin
          // in other case do default...
          originalEditWindowProc(Msg) ;
        end;
      end;
      

      我希望这对你有用。

      问候。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-09
        • 1970-01-01
        • 2013-09-17
        • 1970-01-01
        相关资源
        最近更新 更多