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











