вторник, 27 октября 2009 г.

Перетаскивание объекта оболочки, часть 1: получение IDataObject

Это перевод Dragging a shell object, part 1: Getting the IDataObject. Автор: Реймонд Чен.

Оболочка (shell) даёт вам для этого IDataObject; всё, что вам нужно сделать - просто перетаскивать его (это первая часть в серии из пяти постов).

Начните с пустого VCL-приложения, и добавьте функцию GetUIObjectOfFile из предыдущей статьи. Также вам нужно будет добавить вызовы OleInitialize и OleUninitialize (вызовы CoInitialize(Ex) и CoUninitialize в предыдущей статье за нас делал модуль ComObj) - поскольку теперь мы собираемся использовать полноценный OLE, а не просто COM:
unit Unit1;

interface

...

implementation

...

var
SaveInitProc: Pointer;
NeedToUninitialize: Boolean;

procedure InitComObj;
begin
if SaveInitProc <> nil then
TProcedure(SaveInitProc);
NeedToUninitialize := Succeeded(OleInitialize(nil));
end;

initialization
SaveInitProc := InitProc;
InitProc := @InitComObj;

finalization
if NeedToUninitialize then
OleUninitialize;
end.
Чтобы начать операцию drag/drop, нам понадобится источник для это операции (drop source):
type
TDropSource = class(TInterfacedObject, IDropSource)
protected
// *** IDropSource ***
function QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: Longint): HResult; stdcall;
function GiveFeedback(dwEffect: Longint): HResult; stdcall;
end;

function TDropSource.QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: Longint): HResult;
begin
if fEscapePressed then
Exit(DRAGDROP_S_CANCEL);

if (grfKeyState and (MK_LBUTTON or MK_RBUTTON)) = 0 then
Exit(DRAGDROP_S_DROP);

Result := S_OK;
end;

function TDropSource.GiveFeedback(dwEffect: Longint): HResult;
begin
Result := DRAGDROP_S_USEDEFAULTCURSORS;
end;

Как вы можете видеть, реализация источника необычайно скучна. Даже интересные методы не интересны.

Метод IDropSource.QueryContinueDrag довольно стереотипен. Если была нажата кнопка Escape - тогда мы отменяем операцию перетаскивания. Если кнопки мыши были отпущены, то мы завершаем операцию. В противном случае - просто продолжаем перетаскивание.

Метод IDropSource.GiveFeedback ещё менее интересен. Он просто возвращает DRAGDROP_S_USEDEFAULTCURSORS, чтобы указать, что мы хотим использовать визуальное оформление по-умолчанию.

Верите вы или нет, но теперь у нас есть всё, чтобы перетащить файл.
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
pdto: IDataObject;
pds: IDropSource;
dwEffect: DWORD;
begin
// В настоящей программе, конечно же, вы не будете использовать
// жёстко зашитые пути.
if SUCCEEDED(GetUIObjectOfFile(Handle, 'C:\Windows\clock.avi', IID_IDataObject, pdto)) then
begin
pds := TDropSource.Create;
DoDragDrop(pdto, pds, DROPEFFECT_COPY or DROPEFFECT_LINK, dwEffect);
end;
end;
Чтобы перетащить объект, вам нужны две вещи: перетаскиваемый объект (data object) и источник (drop source). Мы создали наш источник выше, а перетаскиваемый объект приходит к нам из оболочки. Всё, что осталось сделать - начать операцию перетаскивания, вызовом функции DoDragDrop.

Заметьте, что мы указали, что мы разрешаем операции DROPEFFECT_COPY и DROPEFFECT_LINK. Мы специально запретили DROPEFFECT_MOVE, потому что наша программа не представляет собой окно типа папки в Проводнике; пользователь не ожидает, что операция drag/drop приведёт к перемещению файла.

В следующий раз мы добавим поддержку перемещения, просто посмотреть, как это работает.

3 комментария:

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.