"А я все чаще замечаю, что..." в тестовых проектиках для выбора файла нажимать на какую-нибудь кнопку "Browse" и выбирать файл - слишком долго.. Намного быстрее получается перетащить нужный файл (особенно когда надо перепробовать десятки файлов) из окна проводника в свой тестовый проект
Вдруг кому-то пригодится - модуль, облегчающий это действие -несколько шагов, чтобы все заработало:
- добавить .pas файл в проект или путь к файлу в настройки окружения - кому как нравится
- добавить в uses формы, которая будет принимать дропы, ссылку на модуль
- создать 2 обработчика, для реакции на "мышка с обьектом над нами" и "юзер бросил нам обьект"
- ну и создать собственно экземпляр класса в подходящем месте
Где-то вот так:
... type TfrmMain = class(TForm) ... private ... procedure FileDropEvent (Sender: TObject; const Filenames: TWideStrings); procedure FileEnterEvent (Sender: TObject; const Filenames: TWideStrings; var Accept: boolean); public { Public declarations } end; var frmMain: TfrmMain; implementation uses DragDropSupportUnit, ActiveX; var FileDrop: TFileDrop; {$R *.dfm} ... procedure TfrmMain.FileEnterEvent(Sender: TObject; const Filenames: TWideStrings; var Accept: boolean); begin // разрешим дропать только файлы по какому-то правилу - скажем только файлы .mp3 Accept := AnsiLowerCase ( ExtractFileExt ( Filenames [0] ) ) = '.flv'; end; procedure TfrmMain.FileDropEvent(Sender: TObject; const Filenames: TWideStrings); begin // прореагируем на бросание файлов на контрол (файлов может быть и несколько) if Filenames.Count > 1 then begin MessageBox(Handle, 'Many files - will be used only first', 'Warning', MB_OK + MB_ICONINFORMATION); end; edSource.Text := Filenames [0]; end; ... procedure TfrmMain.FormCreate(Sender: TObject); begin ... FileDrop := TFileDrop.Create ( FileDropEvent, FileEnterEvent ); RegisterDragDrop (Handle, FileDrop as IDropTarget); ... end; procedure TfrmMain.FormDestroy(Sender: TObject); begin ... RevokeDragDrop(handle); ... end;
Это все: вызов RegisterDragDrop назначает контрол, handle которого передали параметром, приемником драг-дропа (так что это может быть как вся форма, так и к примеру только поле ввода.. дропаем файл на поле ввода и там тут же появляется имя файла), закрывая программу вертаем все взад.
Код собственно полезного модуля (мне лениво в пятницу вечером делать архив, ложить куда-то на рапиду.. скопипастить в ide да сохранить):
// использование: создать обьект, передав ему указатели на обработчики // OnEnter и OnDrop и зарегистрировать приемник drag-drop-а: // RegisterDragDrop (Handle, FFileDrop as IDropTarget); unit DragDropSupportUnit; interface uses windows, sysutils, widestrings, ActiveX, shellAPI; type TFileDropEvent = procedure (Sender: TObject; const Filenames: TWideStrings) of object; TFileEnterEvent = procedure (Sender: TObject; const Filenames: TWideStrings; var Accept: boolean) of object; TFileDrop = class (TInterfacedObject, IDropTarget) private FDropEvent: TFileDropEvent; FEnterEvent: TFileEnterEvent; FFilenames: TWideStrings; FCanDrop: boolean; public constructor Create (AOnDrop: TFileDropEvent; AOnEnter: TFileEnterEvent); destructor Destroy; override; function DragEnter(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; function DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; function DragLeave: HResult; stdcall; function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult; stdcall; end; implementation { TFileDrop } constructor TFileDrop.Create(AOnDrop: TFileDropEvent; AOnEnter: TFileEnterEvent); begin inherited Create; FDropEvent := AOnDrop; FEnterEvent := AOnEnter; FCanDrop := false; FFilenames := TWideStringList.Create; end; destructor TFileDrop.Destroy; begin FFilenames.Free; inherited; end; function TFileDrop.DragEnter(const dataObj: IDataObject; grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult; var medium: TStgMedium; format: TFormatEtc; fn: array [0..MAX_PATH] of char; fcount, i: integer; begin dataObj._AddRef; format.cfFormat := CF_HDROP; format.ptd := nil; format.dwAspect := DVASPECT_CONTENT; format.lindex := -1; format.tymed := TYMED_HGLOBAL; if dataObj.GetData (format, medium) = S_OK then begin fcount := DragQueryFile (medium.hGlobal, $FFFFFFFF, nil, 0); if fcount > 0 then begin for i := 0 to fcount - 1 do begin DragQueryFile (medium.hGlobal, i, fn, sizeof (fn)); FFilenames.Add ( string ( fn ) ); end; FCanDrop := true; end else FFilenames.Clear; end; if medium.unkForRelease = nil then ReleaseStgMedium (medium); dataObj._Release; if Assigned (FEnterEvent) then FEnterEvent (self, FFilenames, FCanDrop); if FCanDrop then dwEffect := DROPEFFECT_COPY else dwEffect := DROPEFFECT_NONE; Result := S_OK; end; function TFileDrop.DragLeave: HResult; begin FFilenames.Clear; Result := S_OK; end; function TFileDrop.DragOver(grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult; begin if FCanDrop then dwEffect := DROPEFFECT_COPY else dwEffect := DROPEFFECT_NONE; Result := S_OK; end; function TFileDrop.Drop(const dataObj: IDataObject; grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult; begin if Assigned (FDropEvent) and FCanDrop then begin FDropEvent (self, FFilenames); dwEffect := DROPEFFECT_COPY; end else dwEffect := DROPEFFECT_NONE; FFilenames.Clear; Result := S_OK; end; initialization OleInitialize(nil); finalization OleUninitialize; end.
Комментариев нет:
Отправить комментарий