воскресенье, 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? Подпишись, и всегда будете в курсе!

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

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

Сделай автору приятно - оставь комментарий!