2010-09-22 27 views
7

Existe una amplia compatibilidad de arrastrar y soltar en VirtualTreeView de Mike Lischke, y estoy usando TVirtualStringTree, que tiene algunos eventos de arrastrar y soltar, pero no puedo encontrar la forma de conseguir que acepte un drag-drag-y -drop de algunos archivos desde el shell de Windows Explorer, en mi aplicación. Quiero cargar los archivos, cuando se arrastran al control de soltar.¿Cómo se puede arrastrar y soltar un archivo desde el Explorador Shell en un control VirtualTreeView en una aplicación Delphi?

He intentado utilizar un conjunto de terceros de código de Anders Melander, para manejar arrastrar y soltar, sino porque VirtualTreeview ya se registra a sí mismo como un destino de colocación, no puedo usar eso.

corregir: Encontré una solución alternativa: apagueAccepOLEDrop en VT.TreeOptions.MiscOptions. Sería genial si alguien sabe cómo usar VirtualTreeView sin utilizar una biblioteca OLE-shell-drag-drop de terceros y utilizando su amplia compatibilidad con arrastrar y soltar OLE para extraer una lista de nombres de archivo arrastrados desde el Shell.

Respuesta

9

Mi aplicación (funciona muy bien con Delphi 2010. Debe añadir ActiveX, ShellApi a usos para compilar):

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

Utilizo este método para capturar (recibir) archivos arrastrados a un TWinControl desde el explorador.
Puede probarlo en su control. En un TTreeView estándar funciona bien.

Agregue ShellAPI a los usos.

En la sección privada:

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

En OnCreate del formulario:

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

Y los dos procedimientos son los siguientes:

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

espero que esto es muy útil para usted .

Atentamente.

Cuestiones relacionadas