How do you drag and drop a file from Explorer Shell into a VirtualTreeView control in a Delphi application?

后端 未结 2 970
無奈伤痛
無奈伤痛 2020-12-30 12:58

There is extensive drag and drop support in VirtualTreeView by Mike Lischke, and I am using TVirtualStringTree, which has some on-drag-and-drop events, but I can not figure

相关标签:
2条回答
  • 2020-12-30 13:02

    I use this method to capture (receive) files dragged into a TWinControl from explorer.
    You can test it on your control. In a standard TTreeView work fine.

    Add ShellAPI to uses.

    At private section:

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

    At OnCreate of your form:

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

    And the two procedure are these:

    // 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;
    

    I hope that this are usefull for you.

    Regards.

    0 讨论(0)
  • 2020-12-30 13:24

    My implementation (Works very well with Delphi 2010. Must add ActiveX, ShellApi to uses to compile):

    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;
    
    0 讨论(0)
提交回复
热议问题