|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Drag&Drop файлов из проводника (демо)
Периодически в этом подфоруме возникают вопросы "Как перетащить в свое приложение файлы из Проводника Windows?". И я даже пару раз на них отвечал. Посколько мне сегодня с утра нечего делать, я решил написать развернутое пособие на эту тему, благо там ничего сложного нет. Просто обычно формат ответа на вопрос в форуме не подразумевает подробных пояснений, а я все же думаю, что всегда полезно понимать, почему это работает так, а не иначе, и понимать, что ты в данный момент делаешь.
Итак, сложного, как я сказал уже, ничего нет, но есть один нюанс. В большинстве примеров, которые я видел, рассматривается перенос файлов на форму, тогда как обычно в приложении за прием файлов отвечает не форма целиком, а какой-то конкретный элемент формы - TMemo, TListBox и т.п. Делается это потому, что для формы легко организовать перехват сообщения WM_DROPFILES, которым Windows информирует приложение о том, что на него осуществляется перенос файлов. В Delphi для этого существуют т.н. "методы сообщений". Вот тут я писал, как сделать прием файлов формой. Здесь я рассмотрю аналогичную форму, только вместо TMemo буду использовать TListBox. Принципиально это ни на что не влияет, просто TListBox мне в данном случае больше нравится. Как же сделать, чтобы файлы принимались отдельным элементом формы, и не принимались другими? На первый взгляд достаточно заменить вызов: Код:
DragAcceptFiles(Form1.Handle, True); Код:
DragAcceptFiles(ListBox1.Handle, True); То есть задача сводится к тому, чтобы перехватить WM_DROPFILES не в обработчике формы, а непосредственно в обработчике того элемента, который у нас отвечает за прием файлов. Хитрость тут вот чем. И TForm, и TMemo, и TListBox - все это так называемые "оконные" компоненты, т.е. они имеют дескриптор окна, который содержится в свойстве Handle и процедуру окна. Вот до этой процедуры окна нам и надо как-то добраться. Для этого мы напишем свою процедуру окна для ListBox1 и заменим ею стандартную. В WinAPI есть функция SetWindowLong: Код:
SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: Integer): Integer; Сама же процедура окна должна быть описана в виде функции такого вида: Код:
function NewWndProc(Handle: HWND; Msg, WParam, LParam: LongInt): LongInt; stdcall; Итак, чтобы заменить оконную процедуру мы вызываем SetWindowLong: Код:
OldListWndProc := Pointer(SetWindowLong(ListBox1.Handle, GWL_WNDPROC, Integer(@NewListWndProc))); Сама же новая процедура окна будет выглядеть так: Код:
function NewListWndProc(Handle: HWND; Msg, WParam, LParam: LongInt): LongInt; stdcall; //------------------------------------------------------------------------------ // Новая процедура для окна списка //------------------------------------------------------------------------------ var i, Count: Integer; SFileName: Array [0..256] of Char; begin // Мы обрабатываем сообщение WM_DROPFILES if Msg = WM_DROPFILES then begin // Файлов может быть более одного. Чтобы узнать сколько их, // вызываем функцию DragQueryFiles и вместо порядкового номера файла // указываем $FFFFFFFF. Функция вернет количество файлов. Count := DragQueryFile(WParam, $FFFFFFFF, SFilename, SizeOf(SFilename)); // Теперь когда знаем количество файлов, можем перебрать их в цикле // и добавить в список for i := 0 to Count - 1 do begin // Сейчас нам нужно уже конкретное имя файла, // поэтому мы указываем порядковый номер файла и получаем в // переменной SFileName его имя. DragQueryFile(WParam, i, SFileName, SizeOf(SFileName)); // Добавляем имя в список MainForm.AddFileToList(MainForm.ListBox1.Items, SFileName); end; // Windows для переноса файлов выделяла память. // Вызов DragFinish сообщает системе, что память можно освободить DragFinish(WParam); end; // Вызываем старый обработчик сообщений ListBox Result := CallWindowProc(OldListWndProc, Handle, Msg, WParam, LParam); end; Собственно, на этом и все. Остается сделать, как описано выше, ListBox1 приемником файлов Код:
DragAcceptFiles(ListBox1.Handle, True); Код:
SetWindowLong(ListBox1.Handle, GWL_WNDPROC, Integer(OldListWndProc)); Код:
TMyForm = class(TForm) ... private procedure WndMethod(var Msg: TMessage); ... end; Всем, кто дочитал до этого места спасибо. Во вложении полный проект на D2007. |
#2
|
||||
|
||||
У меня не работает. ListBox даже такого сообщения не получает. Windows Vista.
Что делать, когда сломался комп: 1. Если вы юзер - делать ноги. 2. Если ремонтник - делать деньги. 3. Если вы программист - делать вид, что так было задумано. |