среда, 28 октября 2009 г.

Перетаскивание объекта оболочки, часть 2: добавляем перемещение

Это перевод Dragging a shell object, part 2: Enabling the Move operation. Автор: Реймонд Чен.

Давайте предположим, что вы, по какой-то причине, хотели бы поддерживать операцию перемещения (Move) в нашей drag/drop программе.

Давайте реализуем это для какого-нибудь ненужного файла вместо clock.avi. Создайте где-нибудь пустой файл, который вам не жалко будет потерять; скажем, пусть это будет C:\throwaway.txt. Изменим функцию FormMouseDown так:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
pdto: IDataObject;
pds: IDropSource;
dwEffect: Integer;
begin
if SUCCEEDED(GetUIObjectOfFile(Handle, 'C:\throwaway.txt', System.TGUID(IID_IDataObject), pdto)) then
begin
pds := TDropSource.Create;
DoDragDrop(pdto, pds, DROPEFFECT_COPY or DROPEFFECT_LINK or DROPEFFECT_MOVE, dwEffect);
if (dwEffect and DROPEFFECT_MOVE) <> 0 then
DeleteFile('C:\throwaway.txt');
end;
end;
Ох, постойте-ка, некоторые люди считают, что я оправдываю использование жёстко зашитых путей файлов, так что позвольте мне изменить программу так, чтобы она работала с путём из TEdit-а. Этот код будет полным отвлечением от смысла этой статьи, вот почему я его сначала избегал (прим. пер.: в оригинале здесь стоит приём из командной строке; просто Delphi делает это действительно тривиальным изменением, в отличие от C). Лично мне не нравится, когда кто-то даёт мне программу-пример, где 90% кода не относится к технологии, использование которой демонстрирует программа. Я должен раскопать весь код в программе, чтобы найти те 10%, которые действительно имеют значение.
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
pdto: IDataObject;
pds: IDropSource;
dwEffect: Integer;
FileName: String;
begin
FileName := Edit1.Text;
if SUCCEEDED(GetUIObjectOfFile(Handle, FileName, System.TGUID(IID_IDataObject), pdto)) then
begin
pds := TDropSource.Create;
DoDragDrop(pdto, pds, DROPEFFECT_COPY or DROPEFFECT_LINK or DROPEFFECT_MOVE, dwEffect);
if (dwEffect and DROPEFFECT_MOVE) <> 0 then
DeleteFile(FileName);
end;
end;
Вот теперь, я надеюсь, вы счастливы.

На чём я остановился? Ах, да. Объяснение первой части изменений в коде, который теперь находится гораздо выше, благодаря отвлечению не по теме.

Теперь, когда мы разрешили операцию перемещения, нам нужно проверить, не будет ли конечным эффектом DROPEFFECT_MOVE, который говорит нам: "приёмник перетаскивания (drop target) хочет выполнить перемещение, но пока он смог сделать только копирование; пожалуйста, закончите операцию перетаскивания, удалив оригинал".

Заметьте, что флаг DROPEFFECT_MOVE не означает: "была совершена операция перемещения" . Скорее, он говорит нам, что приёмник хочет, чтобы мы удалили оригинал. Если приёмник сам сумеет удалить оригинал (или просто переместить файл напрямую) - тогда вы не получите флага DROPEFFECT_MOVE.

Одним из случаев, когда флаг DROPEFFECT_MOVE даже не означает, что была вообще выполнена операция перемещения, является перетаскивание объекта на иконку "Incinerator" (прим. пер.: как я понял, это такая сторонняя программа, которая удаляет всё, что вы в неё кидаете. Хотя может быть имелась ввиду Корзина?). В этом случае Incinerator вернёт DROPEFFECT_MOVE даже не делая копию. Результат: объект удаляется. Возможно, более лучшим именем для DROPEFFECT_MOVE было бы DROPEFFECT_DELETEORIGINAL.

Если объект перетаскивания (data object) представляет файл, то оболочка сама неплохо соображает, как переместить файл вместо его копирования и просьбы к вам удалить оригинал. Обычно вы будете получать DROPEFFECT_MOVE только если объект перетаскивания не представляет собой файл, потому что в этом случае оболочка не знает, как удалять оригинал.

Но что если вам нужно было узнать, было ли совершено перемещение, вне зависимости от того, сумел ли приёмник оптимизировать перемещение? Мы посмотрим на это в следующий раз.

(Кстати, если вы выполните команду перемещения над нашим файлом throwaway, не забудьте вернуть его обратно перед следующим запуском!)

Комментариев нет:

Отправить комментарий

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

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

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

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

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