Shouldercannon
Помогающий
Offline
|
|
« : 15-12-2011 14:36 » |
|
Данный поток построен верно? unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP;
type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure TNewThread_ThreadTerminate(Sender: TObject); private { Private declarations } public { Public declarations } end;
TNewThread = class(TThread) private { Private declarations } protected procedure Execute; override; end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); var NewThread: TNewThread; begin NewThread := TNewThread.Create(True); // Поток создан и остановлен NewThread.FreeOnTerminate := True; // Уничтожить поток после завершения работы NewThread.Resume; // Запуск потока NewThread.OnTerminate := TNewThread_ThreadTerminate; end;
procedure TNewThread.Execute; var HTTP: TIdHTTP; TMS: TMemoryStream; begin HTTP := TIdHTTP.Create(nil); TMS := TMemoryStream.Create; try try HTTP.Get('http://img.yandex.net/i/www/logo.png', TMS); TMS.SaveToFile('logo.png'); except end; finally HTTP.Free; TMS.Free; end; end;
procedure TForm1.TNewThread_ThreadTerminate(Sender: TObject); begin // Что-то end;
end. Как можно TNewThread_ThreadTerminate описать в потоке TNewThread = class(TThread), а не отдельно, если это вообще возможно?
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #1 : 15-12-2011 15:43 » |
|
NewThread.Resume; // Запуск потока NewThread.OnTerminate := TNewThread_ThreadTerminate; Мне кажется, сначала нужно закончить настройку, а потом будить поток. Особенно если это касается обработчика завершения потока. Быть может по ошибке поток завершится раньше, чем будет установлен обработчик. Как можно TNewThread_ThreadTerminate описать в потоке TNewThread = class(TThread), а не отдельно, если это вообще возможно? Если я правильно понял вопрос, то нужно создать класс-потомок TNewThread и в его конструкторе добавить в качестве обработчика собственный метод. Тогда все экземпляры нового класса будут иметь этот обработчик.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
zubr
Гость
|
|
« Ответ #2 : 15-12-2011 16:43 » |
|
Я бы сделал так: type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private procedure TNewThread_ThreadTerminate(Sender: TObject); public { Public declarations } end;
TNewThread = class(TThread) private
protected procedure Execute; override; public constructor Create(TerminateEvent: TNotifyEvent); overload; end;
var Form1: TForm1;
implementation
{$R *.dfm}
{ TNewThread }
constructor TNewThread.Create(TerminateEvent: TNotifyEvent); begin inherited Create(False); OnTerminate := TerminateEvent; FreeOnTerminate := True; end;
procedure TNewThread.Execute; var HTTP: TIdHTTP; TMS: TMemoryStream; begin HTTP := TIdHTTP.Create(nil); TMS := TMemoryStream.Create; try try HTTP.Get('http://img.yandex.net/i/www/logo.png', TMS); TMS.SaveToFile('logo.png'); except end; finally HTTP.Free; TMS.Free; end; end;
{ TForm1 }
procedure TForm1.TNewThread_ThreadTerminate(Sender: TObject); begin MessageBox(0, 'NewThread Terminated', nil, MB_OK); end;
procedure TForm1.Button1Click(Sender: TObject); begin TNewThread.Create(TNewThread_ThreadTerminate); end;
Как можно TNewThread_ThreadTerminate описать в потоке TNewThread = class(TThread), а не отдельно, если это вообще возможно?
А смысл? Если что то надо сделать в самом потоке по его завершению, то для этого можно вставить какой то код или метод в конец метода Execute. Или переопределить метод Destroy и там выполнить нужный код по завершении потока. Имеет смысл иметь обработчик OnTerminate в другом потоке, который должен знать, что поток NewThread завершился.
|
|
« Последнее редактирование: 15-12-2011 16:46 от zubr »
|
Записан
|
|
|
|
Shouldercannon
Помогающий
Offline
|
|
« Ответ #3 : 19-12-2011 08:17 » |
|
От теории к практике. Вот, что получилось сделать. Возможно, допущены ошибки. TNewThread = class(TThread) private { Private declarations } s: string; Bool: Boolean; protected procedure SyncProc; procedure Execute; override; procedure DoTerminate; override; end;
var Form1: TForm1; a: string; DownloadStatus: Boolean;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); var NewThread: TNewThread; begin Button1.Enabled := False;
NewThread := TNewThread.Create(True); // Поток создан и остановлен NewThread.FreeOnTerminate := True; // Уничтожить поток после завершения работы NewThread.Resume; // Запуск потока end;
procedure TNewThread.Execute; var HTTP: TIdHTTP; MS: TMemoryStream; begin Bool := True; // Статус выполнения операции (успешно)
HTTP := TIdHTTP.Create(nil); MS := TMemoryStream.Create; try try HTTP.Get('http://rvs.ucoz.ru/files/programs/il2sfbc_update.7z', MS); MS.SaveToFile('il2sfbc_update.7z'); except on E: Exception do begin Bool := False; // Статус выполнения операции (накрылось медным тазом) s := E.Message; end; end; finally HTTP.Free; MS.Free; end;
Synchronize(SyncProc); // Синхронизация с основным потоком end;
procedure TNewThread.SyncProc; begin DownloadStatus := Bool; // Синхронизация Boolean a := s; // Синхронизация string end;
procedure TNewThread.DoTerminate; begin // Что-то... Если нужно до вызова внешнего OnTerminate (если назначен) inherited; // Что-то... Если нужно после вызова внешнего OnTerminate (если назначен) Form1.Button1.Enabled := True; if DownloadStatus then MessageBox(0, 'Скачивание прошло успешно', 'Информация', MB_ICONInformation) else MessageBox(0, PChar('Произошла ошибка при скачивании. ' + a), 'Ошибка', MB_ICONError) end; Верно?
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #4 : 19-12-2011 08:32 » |
|
Shouldercannon, чтобы тебе кто-то сказал, верно или неверно, он сперва должен знать, что тебе нужно получить в результате.
А так - это просто сферический класс в вакууме.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Shouldercannon
Помогающий
Offline
|
|
« Ответ #5 : 19-12-2011 08:54 » |
|
Shouldercannon, чтобы тебе кто-то сказал, верно или неверно, он сперва должен знать, что тебе нужно получить в результате.
А так - это просто сферический класс в вакууме.
Я скачиваю в потоке файл, а по завершению этой операции вывожу сообщение о проделанной работе. Во время работы потока я задействовал Boolean, который отображает статус проделанной работы и string, который держит текст ошибки. После завершения работы потока я делаю синхронизацию переменных потока с переменными основного потока. Ещё интересует момент с Button1.Enabled := False;/True;, такое обращение к кнопке допустимо в соответсвующих процедурах?
|
|
« Последнее редактирование: 19-12-2011 08:56 от Shouldercannon »
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #6 : 19-12-2011 09:25 » |
|
1. Все равно делаешь криво: NewThread := TNewThread.Create(True); // Поток создан и остановлен NewThread.FreeOnTerminate := True; // Уничтожить поток после завершения работы NewThread.Resume; // Запуск потока 2. Button1.Enabled := False;/True; надо синхронизировать с GUI-потоком.
|
|
|
Записан
|
|
|
|
Shouldercannon
Помогающий
Offline
|
|
« Ответ #7 : 19-12-2011 10:36 » |
|
1. Все равно делаешь криво: NewThread := TNewThread.Create(True); // Поток создан и остановлен NewThread.FreeOnTerminate := True; // Уничтожить поток после завершения работы NewThread.Resume; // Запуск потока 2. Button1.Enabled := False;/True; надо синхронизировать с GUI-потоком.
По поводу первого: не понял выписку кода. По поводу второго: как сделать сихронизацию с GUI-потоком?
|
|
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #8 : 19-12-2011 11:05 » |
|
По поводу первого: не понял выписку кода.
Инициализацию потока красивее делать в консрукторе потока. Пример я тебе показывал. По поводу второго: как сделать сихронизацию с GUI-потоком?
Использовать метод Synchronize
|
|
|
Записан
|
|
|
|
Shouldercannon
Помогающий
Offline
|
|
« Ответ #9 : 19-12-2011 12:32 » |
|
Как производить синхронизацию переменных знаю Ответ #3, а вот с кнопками не разу не делал.
|
|
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #10 : 19-12-2011 13:11 » |
|
А какая разница? Form1.Button1.Enabled - тоже переменная, только устанавливаемая через свойство.
|
|
|
Записан
|
|
|
|
Shouldercannon
Помогающий
Offline
|
|
« Ответ #11 : 19-12-2011 13:14 » |
|
Значит вместо Button1.Enabled := False; нужно писать Form1.Button1.Enabled := False; ?
|
|
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #12 : 19-12-2011 13:25 » |
|
Значит вместо Button1.Enabled := False; нужно писать Form1.Button1.Enabled := False; ? Не понял. А причем здесь синхронизация? Это вопрос по области видимости переменных. Естественно, если ты устанавливаешь свойство Button1.Enabled в методе класса TNewThread, то надо указывать Form1.Button1.Enabled, а иначе все равно компилятор не пропустит.
|
|
|
Записан
|
|
|
|
Shouldercannon
Помогающий
Offline
|
|
« Ответ #13 : 19-12-2011 14:42 » |
|
Совсем загнался. В Execute и DoTerminate потока обращаемся к свойствам чего-либо через Form1 или через ту форму, где этот поток. А то речь пошла про сихронизацию Button1.Enable и совсем запутался.
|
|
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #14 : 19-12-2011 17:52 » |
|
Как все запущено. Судя по всему ты где то скопипастил код без всякого понятия. Надо изучать литературу по Object Pascal по теме ООП: классы, объекты, область видимости. Извини, объяснять элементарные вещи из учебника нет никакого желания. Педагогика - не моя стихия
|
|
|
Записан
|
|
|
|
|