Newsgroup: it.comp.lang.delphi
Titolo: Drag'n'drop di files nella form (come si fa?)

Ciao a tutti.
Pensate a un programmino semplice semplice, al quale manca la parola:
ovvero la possibilita' di permettere all'utente di trascinare un file
da una finestra explorer alla form.
Non so proprio come fare per otterene tale miracolo,  e ringrazio sin
d'ora chi di voi mi dara' una mano.
grazie
Andrea Darmody
dar...@neofox.net

 da una finestra explorer alla form.
ti rispondo col codice del componente TDropHelperEx, che ho creato in 
collaborazione con Andrea Raimondi, che fa proprio ciņ che chiedi: lo piazzi 
su una form e questa diventa automaticamente in grado di accettare il drop 
di files esterni (al momento del drop viene scatentato l'evento OnDropFiles 
e nella proprietą FileNames trovi la lista dei file droppati).
Nota che puoi utilizzare TDropHelperEx anche come componente interno di 
altri componenti derivati per es. da TWinControl per far sģ che questi (ma 
non la form che li ospita) acquisiscano la capacitą di accettare il drop di 
file esterni (per questo esempio rimando al termine del codice del 
componente).
--------INIZIO CODICE COMPONENTE--------
unit DropHelperEx;
(***********************************************************)
(*        by Mauro Falzari (
open....@email.it
)
(*
(*        ESTENSIONE DI TDropHelper di Andrea Raimondi
(*
(***********************************************************)
interface
uses
  Windows, Classes, Messages;
type
  TDropHelperEx = class(TComponent)
  private
    FDropHandle: THandle;
    FFileCount: Integer;
    FFileNames: TStringList;
    FParentOldWndProc: TWndMethod;
    FOnDropFiles: TNotifyEvent;
    procedure DropFiles;
    function GetFiles(const Index: Integer): string;
    function GetFileNames: TStrings;
    function GetFileNameSize(const Index: Integer): Integer;
    procedure SetDropHandle(const Value: THandle);
    procedure SubClassWndProc(var Msg: TMessage);
  public
    constructor Create(AnOwner: TComponent); override;
    destructor Destroy; override;
    property FileNames: TStrings read GetFileNames;
    { lista dei nomi dei file oggetto dell'operazione di drop }
    property DropHandle: THandle read FDropHandle write SetDropHandle;
    { proprietą per far funzionare il componente in modalitą "manuale" }
  published
    property OnDropFiles: TNotifyEvent read FOnDropFiles write FOnDropFiles;
    { evento che si verifica al momento del drop di file sul componente
    proprietario; infatti non č possibile utilizzare gli eventi OnDragDrop e
    OnDragOver del componente proprietario per il semplice fatto che non si
    verificano }
  end;
procedure Register;
implementation
uses
  Controls, SysUtils, ShellAPI;
{$R *.dcr}
procedure Register;
begin
  RegisterComponents('MF', [TDropHelperEx]);
end;
constructor TDropHelperEx.Create(AnOwner: TComponent);
begin
  inherited Create(AnOwner);
  FFileNames:= TStringList.Create;
  if AnOwner is TWinControl then
    with AnOwner as TWinControl do
    begin
      DragAcceptFiles(Handle, True);
      FParentOldWndProc:= WindowProc;
      WindowProc:= SubClassWndProc;
    end
end;
destructor TDropHelperEx.Destroy;
begin
  FFileNames.Free;
  if Owner is TWinControl then
    with Owner as TWinControl do
    begin
      DragAcceptFiles(Handle, False);
      WindowProc:= FParentOldWndProc;
    end;
  inherited Destroy;
end;
procedure TDropHelperEx.DropFiles;
begin
  if Assigned(FOnDropFiles) then
    FOnDropFiles(Self);
end;
function TDropHelperEx.GetFileNames: TStrings;
var
  c: Integer;
begin
  FFileNames.Clear;
  FFileNames.Capacity:= FFileCount;
  for c:= 0 to Pred(FFileCount) do
    FFileNames.Add(GetFiles(c));
  Result:= FFileNames;
end;
function TDropHelperEx.GetFileNameSize(const Index: Integer): Integer;
begin
  Result:= DragQueryFile(FDropHandle, Index, nil, 0);
end;
function TDropHelperEx.GetFiles(const Index: Integer): string;
var
  PCharFName: PChar;
  PCharSize: Integer;
begin
  PCharSize:= GetFileNameSize(Index);
  GetMem(PCharFName, PCharSize + 1);  //aggiunto + 1
  DragQueryFile(FDropHandle, Index, PCharFName, PCharSize + 1);  //aggiunto 
+ 1
  Result:= string(PCharFName);
  FreeMem(PCharFName);
end;
procedure TDropHelperEx.SetDropHandle(const Value: THandle);
const
  NUM_OF_FILES_ID = $FFFFFFFF;
begin
  if FDropHandle <> Value then
  begin
    FDropHandle:= Value;
    FFileCount:= DragQueryFile(FDropHandle, NUM_OF_FILES_ID, nil, 0);
    DropFiles;
  end;
end;
procedure TDropHelperEx.SubClassWndProc(var Msg: TMessage);
begin
  if Msg.Msg = WM_DROPFILES then
    SetDropHandle(Msg.WParam)
  else
    FParentOldWndProc(Msg);
end;
end.
---------FINE CODICE COMPONENTE----------
Esempi:
Form che accetta il drop di files:
--------
procedure TForm1.DropHelperEx1DropFiles(Sender: TObject);
begin
  ListBox1.Items.AddStrings(DropHelperEx1.FileNames);
//oppure    ListBox1.Items:= DropHelperEx1.FileNames;
end;
--------
Componente che accetta il drop di files:
--------
type
  TForm1 = class(TForm)
  {....}
  private
    procedure AcceptFiles(Sender: TObject);
{....}
implementation
uses
  DropHelperEx;
 
{$R *.dfm}
procedure TForm1.AcceptFiles(Sender: TObject);
begin
  ListBox1.Items.AddStrings((Sender as TDropHelperEx).FileNames);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  with TDropHelperEx.Create(ListBox1) do
    OnDropFiles:= AcceptFiles;
end;
-- 
Mauro Falzari.
"Se guardi nell'abisso, anche l'abisso guarda in te."
(Friedrich Nietzsche)

 (ecc)

 ha scritto nel messaggio
news:akss39$i0e$1...@newsreader.mailgate.org...

Io uso questo metodo (tra l'altro trovato in Internet)
type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    procedure WMDROPFILES(var Msg: TMessage);
    procedure LBWindowProc(var Message: TMessage);
    procedure AddFile(sFileName: string);
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
  OldLBWindowProc: TWndMethod;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
  OldLBWindowProc := ListBox1.WindowProc; // store defualt WindowProc
  ListBox1.WindowProc := LBWindowProc; // replace default WindowProc
  DragAcceptFiles(ListBox1.Handle, True) // now ListBox1 accept dropped
files
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
  ListBox1.WindowProc := OldLBWindowProc;
  DragAcceptFiles(ListBox1.Handle, False)
end;
procedure TForm1.LBWindowProc(var Message: TMessage);
begin
  if Message.Msg = WM_DROPFILES then
    WMDROPFILES(Message); // handle WM_DROPFILES message
  OldLBWindowProc(Message)
  // call default ListBox1 WindowProc method to handle all other messages
end;
procedure TForm1.WMDROPFILES(var Msg: TMessage);
var
  pcFileName: PChar;
  i, iSize, iFileCount: integer;
begin
  pcFileName := ''; // to avoid compiler warning message
  iFileCount := DragQueryFile(Msg.wParam, $FFFFFFFF, pcFileName, 255);
  for i := 0 to iFileCount - 1 do
  begin
    iSize := DragQueryFile(Msg.wParam, i, nil, 0) + 1;
    pcFileName := StrAlloc(iSize);
    DragQueryFile(Msg.wParam, i, pcFileName, iSize);
    if FileExists(pcFileName) then
      AddFile(pcFileName); // method to add each file
    StrDispose(pcFileName)
  end;
  DragFinish(Msg.wParam)
end;
procedure TForm1.AddFile(sFileName: string);
begin
  ListBox1.Items.Add (sFilename)
end;
end.