воскресенье, 17 апреля 2011 г.

Работа с файлообменником Часть 2

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

Дизайн не многим отличается от предыдущего, но мы добавили компонент Gauge он будет отображать прогресс(%) и добавили информацию сколько закачено и, размера файла. Кнопка Скопировать URL  наверняка вам уже понятно что тут подразумевается(копирование ссылки на файл).

Создайте новый проект, далее создайте объект потока File - New - Other - Thread Object объект потока назовем NewThread. Теперь посмотрим на код созданного потока.

unit Unit2;

interface

uses
Classes;

type
NewThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;

implementation

{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure NewThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }

{ NewThread }

procedure NewThread.Execute;
begin
{ Place thread code here }
end;

end.
 
В процедуре Execute должен быть написан наш код который мы хотим добавить в многопоточность. У меня получился такой код:
procedure NewThread.Execute;
var
Data: TIdMultiPartFormDataStream; // Сюда будут загружаться данные, которые нужно заполнить
Http: TidHTTP;
begin
// Денамически создаем компонент IdHTTP
Http := TIdHttp.Create(Nil);
Http.HandleRedirects := True;
Http.Request.Referer := 'http://realfile.ru/';
Http.Request.UserAgent := 'Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.7.62 Version/11.01';
Http.OnWork := HttpWork;
Http.OnWorkBegin := HttpWorkBegin;
Http.OnWorkEnd := HttpWorkEnd;
// Добавили события к созданому денамическому компоненту idHTTP
Data := TIdMultiPartFormDataStream.Create;
Data.AddFile('file', Form1.FilePath.Text, 'multipart/form-data'); // Заполняем файлом
Data.AddFormField('descr', form1.FileDescr.Text); // Описание
Data.AddFormField('password', form1.password.Text); // Пароль
S := Http.Post('http://realfile.ru/', Data); // ссылка и отправляем пос запрос
S := Copy(S, Pos('value="',S)+7, Pos('" size="36">',S) - Pos('value="',S)-7);
Synchronize(ShowUrl);//Чтобы передавать какие то значения в процедуру, она должна вводится методом Synchronize
Data.Free; // Удалаем переменную, (освобождаем память)
end;

Код немного различается от предыдущего. Мы создали динамически компонент idHTTP и создали к нему события, но нужно прописать процедуры событий, и добавить в uses модули.

uses
Classes, IdMultiPartFormData,IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP, SysUtils;

type
NewThread = class(TThread)
private
S: String; // Тут будет результат отправки запроса
protected
procedure Execute; override;
procedure ShowUrl;
procedure HTTPWorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer);
procedure HTTPWork(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
procedure HTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode);

end;

Мы добавили переменную S в раздел private для того что бы можно было работать с ней в дальнейшем, так как у нас процедура ShowUrl передает результат на основную форму(программу). Процедура ShowUrl выглядит так:

procedure NewThread.ShowUrl;
begin
Form1.Url.Text := S;
end;

Основу программы мы сделали, нам осталось добавить (сколько программа загрузила КБ, сколько всего КБ). В процедурах HTTPWorkBegin, HTTPWork, HTTPWorkEnd. Напишим следуещий код:

procedure NewThread.HTTPWork(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCount: Integer);
begin
Form1.Gauge1.Progress := AWorkCount; // Сколько уже загрузили КБ
form1.Label5.Caption := 'Закачено: ' + IntToStr(AWorkCount div 1024) + ' КБ';
end;

procedure NewThread.HTTPWorkBegin(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCountMax: Integer);
begin
Form1.Gauge1.MaxValue := AWorkCountMax; // Получаем размер загружаемого файла, и добавляем в максимальное значения Gauge1
form1.Label6.Caption := ' из ' +IntToStr(AWorkCountMax div 1024)+ ' КБ';
end;

procedure NewThread.HTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode);
begin
form1.Caption := 'Загрузка завершена!';
end;

Вроде все, код для многопоточности мы написали:

unit Unit2;

interface

uses
Classes, IdMultiPartFormData,IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP, SysUtils;

type
NewThread = class(TThread)
private
S: String; // Тут будет результат отправки запроса
protected
procedure Execute; override;
procedure ShowUrl;
procedure HTTPWorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer);
procedure HTTPWork(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
procedure HTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode);

end;

implementation

uses Unit1;

{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure NewThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }

{ NewThread }

procedureNewThread.Execute;
var
Data: TIdMultiPartFormDataStream; // Сюда будут загружаться данные, которые нужно заполнить
Http: TidHTTP;
begin
Http := TIdHttp.Create(Nil);
Http.HandleRedirects := True;
Http.Request.Referer := 'http://realfile.ru/';
Http.Request.UserAgent := 'Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.7.62 Version/11.01';
Http.OnWork := HttpWork;
Http.OnWorkBegin := HttpWorkBegin;
Http.OnWorkEnd := HttpWorkEnd;
// Добавили события к созданому денамическому компоненту idHTTP
Data := TIdMultiPartFormDataStream.Create;
Data.AddFile('file', Form1.FilePath.Text, 'multipart/form-data'); // Заполняем файлом
Data.AddFormField('descr', form1.FileDescr.Text); // Описание
Data.AddFormField('password', form1.password.Text); // Пароль
S := Http.Post('http://realfile.ru/', Data); // ссылка и отправляем пос запрос
S := Copy(S, Pos('value="',S)+7, Pos('" size="36">',S) - Pos('value="',S)-7);
Synchronize(ShowUrl);//Чтобы передавать какие то значения в процедуру, она должна вводится методом Synchronize
Data.Free; // Удалаем переменную, (освобождаем память)

end;

procedure NewThread.HTTPWork(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCount: Integer);
begin
Form1.Gauge1.Progress := AWorkCount;
form1.Label5.Caption := 'Скачано: ' + IntToStr(AWorkCount div 1024) + ' КБ';
end;

procedure NewThread.HTTPWorkBegin(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCountMax: Integer);
begin
Form1.Gauge1.MaxValue := AWorkCountMax;
form1.Label6.Caption := ' из ' +IntToStr(AWorkCountMax div 1024)+ ' КБ';
end;

procedure NewThread.HTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode);
begin
form1.Caption := 'Загрузка завершена!';
end;

procedure NewThread.ShowUrl;
begin
Form1.Url.Text := S;
end;

end.

Переходим на основную форму, на кнопку 'Загрузить' пишем следующий код:

Var
Potok: NewThread;
begin
Potok := NewThread.Create(True); // Создаем поток
Potok.Resume; // Запускаем
Potok.Priority := tpLower; // Приоритет низкий
end;


Кнопка Копировать URL:

ClipBoard.SetTextBuf(PChar(Url.Text));

Не забываем добавить в uses модуль, ClipBrd.
Ну вот и пожалуй все, не буду описывать кнопку выбрать и т.п так как в предыдущий статьи это было описано! Еще не подписался на RSS feed? Подпишись, и всегда будете в курсе!

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

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