Скачиваем файлы из интернета при помощи DelphiИсточник: delphi Вадим К.
Задача: скачать файл по http в указанную папку с использованием потока. Делаем форму Бросаем на форму два TEdit, TProgressBar, одну кнопку и TSaveDialog. Для кнопки пишем маленький обработчик: //Этой строкой мы скопируем имя файла SaveDialog1.FileName:=copy(Edit1.Text,LastDelimiter('\⁄',Edit1.Text)+1,maxint); Теперь на форму добавим IdHTTP и кнопку (Button2) с надписью "начать закачку". Делаем поток С обработчиком пока повременим, а напишем самое сложное - класс для потока. {$R *.dfm} Первые две строки сделаны для того, чтобы было видно, где вписать код. И нажимаем Ctrl+Shift+C. Delphi допишет немного кода. Он теперь будет выглядеть так: type Компонент idHTTP был брошен на форму только с одной целью - чтобы Delphi добавила все заголовочные файлы в uses. Потом его можно будет удалить. Но можно и самостоятельно вписать в uses файл idHTTP. Главный код потока Итак, код обработчика: procedure TDownLoader.Execute; Помните, что в этой процедуре нельзя напрямую обращаться к компонентам формы и другим потокам. Это делается специальным образом, который называется синхронизацией. Запускаем поток И наконец, обработчик для кнопки: procedure TForm1.Button2Click(Sender: TObject); Теперь наш код уже может качать, но у нас нет прогресса, нет уведомления о завершении закачки. Дополнительные возможности Добавим для начала уведомление о закачке. Добавим в public часть формы добавим строку: public и нажмём Ctrl+Shift+C. Появится новый обработчик, который мы дополним одной строкой. Я вывожу просто сообщение о готовности. Помните, эта процедура будет вызваться, когда поток выполнит всю свою работу (завершится процедура Execute). Только в этой процедуре можно одновременно обращаться к компонентам формы и данным потока. procedure TForm1.thrTerminate(Sender: TObject); И добавим её вызов в обработчике кнопки запуска: //Поток должен удалить себя по завершению своей работы Делаем прогресс Теперь у нас осталась ещё одна проблема - оживить прогресс-бар. Но здесь нас подстерегает один момент: с потока нельзя просто так обращаться к компонентам формы. Точнее, правило звучит так: с одного потока нельзя обращаться к данным другого потока (переменным, коду) без специальных методов. Таких методов есть два. Первый - мы останавливаем один поток, а второй на это время получает доступ к его переменным. Либо второй поток просит первый исполнить какой-то код, а сам на это время засыпает. Способ два, которым мы и воспользуемся - это посредник. Мы шлём сообщение посреднику, чтобы он сообщил другому потоку (а может и группе), чтобы он что-то сделал. Этот способ хорош тем, что поток может обрабатывать сообщения не по принуждению, а по возможности. То есть сообщения стают в очередь. В качестве посредника мы выберем саму среду Windows. Итак, Windows при посылке сообщения позволяет передавать два целочисленных параметра. Первый мы будем использовать как идентификатор действий, второй - как дополнительный параметр. Поехали дальше. После uses перед Type вставим строку: const А в объявлении формы добавим новый метод: procedure MyProgress(var msg:TMessage);message MY_MESS; И заветное Ctrl+Shift+C В свежесозданном обработчике пишем такое: procedure TForm1.MyProgress(var msg: TMessage); То-есть, если передали тип операции 0 - значит нужно инициализировать прогресс. Передали 1 - нужно выставить позицию. Как именно - указано в другом параметре (msg.LParam). А теперь возвращаемся к нашим обработчикам IdHTTP, которые мы оставили без реализации. Туда нужно вписать всего по строчке. Ниже приведена реализация. procedure TDownLoader.IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode; Заключение Естественно, есть ещё несколько способов всё синхронизировать. Но такой способ мне кажется очень простым и надёжным, так как не будет блокировок, сообщения будут обрабатываться по мере возможности (по мере сил :-)). В сопутствующем архиве вы найдёте полный рабочий пример. Он будет компилироваться на Delphi 2006 и Indy 10. На 7 Delphi сходу может не скомпилироваться, но если вы будете делать вручную и немного думать, то всё заработает. Причина - с Delphi 7 поставляется более старая версияIndy. |