Как это сделано? Drag & Drop - объектный подхо

Как это сделано? Drag & Drop - объектный подхо

Drag & Drop

Продолжаем начатое дело. Итак по результатам голосования (здесь) выяснилось что большинство программистов интересует как сделать Drag & Drop. Как перетянуть текст из скажем ворда в вашу программу, или имя файла в Total commander? Вот об этом наш выпуск. Не-программисты идут дальше...

----------------------<cut>----------------------

Надеюсь, все представляют что такое drag&drop? И как сделать перетаскивание внутри вашей программы? Еще не знаете — тогда читать здесь и здесь. Мы же поговорим о более сложном варианте — перетаскивание между РАЗЛИЧНЫМИ программами.

Данная возможность реализуется с использованием OLE2, так что необходимо понимание таких вещей как interface и технологии COM в целом. Поэтому я и назвал — объектный подход. А вы думали объектная обертка операции drag & drop ? — будет вам и это ;)))

Итак вот исходный код — скачайте его

Необходимо зарегистрироваться чтобы прочитать текст

1. Создаем обычное VCL — приложение, в главный модуль подключаем ActiveX — ну как нам без него :))
2. В OnCreate главной формы пишем

OLEInitialize(nil);

Это очень важный момент — иначе все остальное работать просто не будет.

3. Приведенный выше пример иллюстрирует сразу две техники — прием данных с внешних приложений и перетаскивание данных во внешние приложения.

Поговорим вначале о первом.

Для того чтобы Ваша программа понимала что в нее сбрасывают (drop) данные нужно создать экземпляр объекта интерфейса IDropTarget и зарегистрировать ваше главное окно (main Form) в OLE Drag And Drop.

dropTarget:=TDropTarget.Create;
 dropTarget.OnFileDropped:=OnFileDropped;

 RegisterDragDrop(Handle,dropTarget); // регистрации в OLE

Разумеется интерфейс мы реализуем сами
// Drop interface

   TMyDragDropEvent = procedure (const Value:string;Pos:TPoint) of object;

   TDropTarget = class(TInterfacedObject,IDropTarget)
    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;
   private
    FFileDropped:TMyDragDropEvent;
   public
    property OnFileDropped:TMyDragDropEvent read FFileDropped write FFileDropped;
   end;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

{ TDropTarget }

function TDropTarget.DragEnter(const dataObj: IDataObject; grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult;
begin
 dwEffect:=DROPEFFECT_COPY;
 Result:=S_OK;
end;

function TDropTarget.DragLeave: HResult;
begin
 Result := S_OK;
end;

function TDropTarget.DragOver(grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult;
begin
 dwEffect:=DROPEFFECT_COPY;
 Result:=S_OK;
end;

function TDropTarget.Drop(const dataObj: IDataObject; grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult;
var
 etc:TFormatETC;
 med:TSTGMedium;
 res:Integer;
 fileDropped:array [0..MAX_PATH] of char;
 count,i:Word;
begin
 etc.cfFormat:=CF_HDROP;
 etc.ptd:=nil;
 etc.dwAspect:=DVASPECT_CONTENT;
 etc.lindex:=-1;
 etc.tymed:=TYMED_HGLOBAL;
 res:=dataObj.GetData(etc,med);
 if res=S_OK then
  begin
   count:=DragQueryFile(HDROP(med.hGlobal),$FFFFFFFF,nil,0);
   for i:=0 to count-1 do
    begin
     DragQueryFile(HDROP(med.hGlobal),i,fileDropped,sizeof(fileDropped));
     if Assigned(FFileDropped) then FFileDropped(fileDropped,pt);
    end;
   if med.UnkForRelease<>nil then IUnknown(med.UnkForRelease)._Release else GlobalFree(med.hGlobal);
  end;
 dwEffect:=DROPEFFECT_COPY;
 Result:=S_OK;
end;

Тут особо комментировать нечего — самый важный метод это Drop — в нем наша программа получает данные из глобальной области памяти OLE (кто писал хуки или работал Mem Mapped Files — то это уже видел).

Вторая техника — перетаскивание СВОИХ данных в другую программу — несколько сложнее реализуем.
Требуется несколько шагов:
1. Регистрация поддерживаемых форматов и их количества.
2.Создание экземпляров объектов интерфесов IDataObject и IDropSource
3. Вызов и обработка функции OLE2 : DoDragDrop
4. Привязка все этого к какому то компоненту на форме

Более подробно — в приведенном коде — к сожалению большой размер кода (см файл inlcude\dnd.pas)

Надеюсь статья показалась Вам полезной! Конечно это не идеал, есть много чего доработать и улучшить. Это вам пища для размышлений ;)

C Уважением Ваш Док — http://prodelphi.nnm.ru

Тэги: delphi, drag, drop, programming

Комментарии

    Нет комментариев
комментарии
^ Наверх