Ну что давайте теперь поговорим о том, как можно в потоке обработать запрос GET или POST компонента TIdHTTP. Это довольно распространнено, так как не все делают запросы с помощью сокетов, среди «дельфистов» есть и любители «индюшек» (Indy) и их может даже и большинство, хоть некоторые версии Indy «глючные» на некоторых компилятор, я все равно использую компоненты данной библиотеки. Необходимость запросов POST и GET возникает, например в том случае, если необходимо отпарсить какие-нибудь страницы сайта (получить какие-то данные), перед этим довольно часто бывает — необходимо отправить сначала POST-запрос, а только затем уже получать информацию со страницы. Так вот когда TidHTTP обрабатывает страницу, получает код ее, парсит, отправляет запрос и так далее, то форма (главное окно приложения, программы, все приложение) зависате на это время (на время выполнения данных операций, функций, действий). Для того, чтобы избежать данного зависания в Indy предусмотрен компонент TidAntiFreeze, поставив на форму, помогает избежать зависания данной формы. Но это не то, все равно поставив данный компонент на форму, все равно видно как форму периодически зависает, что также очень и даже очень не удобно и не заметно. В некоторых случаях «прокатывает» Application.ProcessMessages. Но опять же не всегда это дело помогает. Как этого избежать много раз уже говорил и скажу еще раз, так как сам потоки не сильно давно начал изучать и понял их «мощь«, можно избежать с помощью потоков (выполнения действий в фоновом режиме, не мешая работе другим потокам, а главное основному потоку программы). С использованием потоков в Indy могут вернуться и те, кто их не долюбливал, так как теперь можно отправлять почту, смс, запросы, получать запросы и так далеебез зависания, что очень хорошо.
На форме у меня все старые комопненты
Напомню TAntiFreeze на форме у меня нету, так как поставив его на форму, многие скажут, что из-за него форма не зависает, но мы его специально не устанавливаем на форму, чтобы показать, что без данного компонента мы сможем справиться с зависанием формы. Давайте создадим наконец-то наш поток, помним, что за потоки у нас отвечает класс TThread. Я создаю в этом же модуле, вы сможете создать с помощью мастера, а затем в модуль вашего проекта подключить модуль потока, и наоборот. напомню, что для создания с помощью мастера выполняем команду File-New-Other во кладке New выбираем Thread Object. В появившемся окне вводим имя нашего потока и нажимаем «Ок«.
В текущем модуле я описал вот такой вот класс
type
ThreadGet=class(TThread)
private
html:WideString;
protected
procedure ShowResult;
procedure Execute;override;
end;
Далее у меня 2 процедуры в данном классе и переменная. В переменной будет храниться результат, процедура ShowResult - будет этот результат выводить, а Execute - само выполнение нашего потока. Мы сделаем обычный запрос GET к сайту и получим html-код страницы данного сайта, ну и конечно выведем этот html-код в виде сообщения (все это должно происходить без зависания формы, даже если мы не подключены к Интернет). Далее я поставил курсор мыши на процедуру Execute и нажал Shift+Ctrl+C и появились наши процедуры потока, которые и необходимо заполнить (написать выполнения данных процедур, то есть код). Процедура Execute у меня выглядит так
procedure ThreadGet.Execute;
begin
inherited;
html:=Form1.IdHTTP1.Get('https://zaokomtek.ru/');
Synchronize(ShowResult);
end;
Делаем запрос как я показывал, в переменную записываем html-код, далее синхронизируем процедуру вывода результата. Процедура ShowResult у меня выглядит следующим образом
procedure ThreadGet.ShowResult;
begin
if html<>'' then
begin
ShowMessage(html);
html:='';
end;
end;
То есть просто делаем проверку, если в нашей переменной есть html-код, то выводим его, если нету, то ничего не делаем и ждем пока там что-то появиться. Как видите ничего сложного тут нету, все довольно просто и похоже на те примеры по потокам, что я уже приводил. Давайте усовершенствуем нашу программу, и если мы не подключены к Интернет, то выведем об этом сообщение, чтобы пользователь подключился к нему. В сети Интернет и в разных help-ах есть много алгоритмов определения подключен ли компьютер к Интернет, но для меня есть метод в 3 строчки кода, который мне нравится и я его использую. Вспомним наш модуль wininet с помощью функции данного модуля мы будем определять подключены ли мы к сети Интернет или нет. Для этого давайте в Uses подлючим wininet модуль и будем пользоваться необходимыми функциями и процедура данного модуля. Также нам необходим объявить переменную типа DWORD. В ней мы будем записывать наши подлкючения, то есть определить подключены ли мы к сети, к Интернету через модем, через прокси. Для этого в данную переменную необходимо записать следующее (назвал я ее Connecton).
1-есть ли подключение через Интернет, 2 — есть ли подключение через сеть, 3 — есть ли подключение через прокси, тут мы указали эти подключения и функция их будет проверять. Далее я дописал в процедуру потока — Execute и у меня получилось следующее
procedure ThreadGet.Execute;
var
Connection:DWORD;
begin
inherited;
Connection:=1+2+3;
if InternetGetConnectedState(@Connection,0)=True then
begin
html:=Form1.IdHTTP1.Get('https://zaokomtek.ru/');
Synchronize(ShowResult);
end
else
ShowMessage('No Connection to Network');
end;
Как вы поняли функция InternetGetConnectedState проверяет есть ли у нас соединение с сетью, которые перечислены в переменной Connection.
Процедуру ShowResult я оставил без изменения. Теперь на событие OnClick TButton напишем следующий код
procedure TForm1.Button1Click(Sender: TObject);
var
NewThread:ThreadGet;
begin
NewThread:=ThreadGet.Create(False);
NewThread.Resume;
NewThread.Priority:=tpNormal;
end;
Создаем поток, возобновляем, ставим приоритет нормальный вызываем сразу процедуру Execute. Теперь можете установить на форму TEdit и нажать на кнопку и пока получается запрос набрать текст в TEdit, подвинуть форму и увидим, что все нормально и ничего не зависает, продолжение следует…
Автор статьи - Andrey53
Метки: get, idAntifreeze, Idhttp, post, TThread, wininet, многопоточные приложения, поток, потоки
Спасибо за статью! Как обычно информативно.
Я добавил на форму Мемо и попробовал вывести результат в него
procedure ThreadGet.ShowResult;
begin
if html» then
begin
Memo1.Text:= html;
html:=»;
end;
end;
но так не получается, вы не могли бы подсказать как сделать правильно?
А все разобрался сам )
procedure ThreadGet.ShowResult;
begin
if html'' then
begin
Form1.Memo.Lines.Add(html);
ShowMessage('!');
html:='';
end;
end;
Спасибо!