2010-09-22 35 views
7

Mike Lischke propose une prise en charge étendue du glisser-déposer dans VirtualTreeView, et j'utilise TVirtualStringTree, qui propose des événements glisser-déposer, mais je n'arrive pas à comprendre comment l'accepter. -drop de certains fichiers du shell de Windows Explorer, dans mon application. Je veux charger les fichiers, quand ils sont glissés sur le contrôle de chute. J'ai essayé d'utiliser un jeu de code tiers d'Anders Melander, pour gérer le glisser-déposer, mais comme VirtualTreeView s'enregistre déjà comme cible, je ne peux pas l'utiliser.Comment faire glisser et déposer un fichier à partir de l'Explorateur Shell dans un contrôle VirtualTreeView dans une application Delphi?

edit: J'ai trouvé une solution de contournement simple: Désactivez toAcceptOLEDrop dans VT.TreeOptions.MiscOptions. Ce serait génial si quelqu'un connaissait un moyen d'utiliser VirtualTreeView sans utiliser une bibliothèque OLE-shell-glisser-déposer tierce et en utilisant son support étendu de glisser/déposer OLE pour extraire une liste de noms de fichiers tirés du Shell.

Répondre

9

Ma mise en œuvre (Fonctionne très bien avec Delphi 2010. Il faut ajouter ActiveX, ShellAPI à compiler des utilisations):

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

J'utilise cette méthode pour capturer (recevoir) des fichiers glissés dans un TWinControl depuis l'explorateur.
Vous pouvez le tester sur votre contrôle. Dans un travail standard TTreeView bien.

Ajouter ShellAPI aux utilisations.

À section privée:

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

Au OnCreate de votre formulaire:

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

Et les deux procédures sont les suivants:

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

J'espère que ce sont utiles pour vous .

Cordialement.