-
dreamse (22.05.08 23:34) [0]Добрый вечер.
Начал недавно работать с потоками и сталкнулся с такой ситуацией:
MDI приложение
в каждой MDI форме объявлен поток:
TPingThread = class(TThread)
private
public
procedure Execute; override;
procedure UpdateCaption;
end;
метод UpdateCaption служит для синхронизации.
Нужно с
procedure TPingThread.UpdateCaption;
begin
//
end;
как то обратиться к компоненту на форме.
но Self.Mem_ping_result.text такого нет так как форма MDI и создана динамически ...
Вопрос: как в procedure TPingThread.UpdateCaption
передавать данные в компонент на форме ?
пробывал создать глобальную переменную и в потоке писать туда, а потом обычным таймером вгонять данные в Tmemo.
Все работает, но если создать еще одну MDI форму то там тоже будет обновляться почему то данные т.е синхронизироваться с 1 формой ...
где ошибся понять не могу :(
Весь код:
TPingThread = class(TThread)
private
public
procedure Execute; override;
procedure UpdateCaption;
end;
var
FrmPing: TFrmPing;
StartPing:TThread;
PingText:string;
implementation
uses formMain;
{$R *.dfm}
{ TPingThread }
procedure TPingThread.Execute;
begin
inherited;
FreeOnTerminate := true;
....
PingText := PingText + string(Buffer);
....
end;
procedure TFrmPing.RzBitBtn3Click(Sender: TObject);
begin
StartPing := TPingThread.Create(true);
StartPing.Priority := tpLowest;
StartPing.Resume;
end;
procedure TPingThread.UpdateCaption;
begin
self.
// Self.Mem_ping_result.Text := pingText;
end;
procedure TFrmPing.Timer1Timer(Sender: TObject);
begin
if PingText <> '' then
Mem_ping_result.Text := PingText;
end; -
Loginov Dmitry © (23.05.08 00:01) [1]Добавь в описание класса TPingThread дополнительное поле типа TFrmPing и при создании треда (в RzBitBtn3Click) устанавливай его, например так:
StartPing.FrmPing := Self; -
не советую привязывть треды ни к МДИ, ни к каким другим формам. Поток как класс создай вне всяких форм, а уже из форм надо его создавать, запускать и прибивать. Для отображения хода процессов использовать некую общую (например в гл.форме) процедуру, которую вызывать из потоков с использованием Synchronize. Если для отображения надо использовать много параметров разных типов, то использовать дескрипторы, которые надо создавать и инициализировать перед созданием потока, а указатель на него передавать в конструктор потока, как переменную того же типа, что и дескриптор. Ессно, эту переменную надо уложить в поле класса потока. По завершению потока дескриптор должен прибиваться.
-
Перед синхрон-вызовом "отображающей" процедуры поток должен записать в дескриптор данные о текущем статусе или чего там надо показывать и передать ей указатель на "свой" дескриптор.
Либо вообще ничего не вызывать, а в самой отображающей форме через определенные интервалы времени просматривать список дескрипторв потоков, обновляя соответствующие визуальые контролы (например, сетки или листвью) -
dreamse (23.05.08 01:04) [4]> Loginov Dmitry © (23.05.08 00:01) [1]
То же самое. одновременно работают если несколько форм создать :(
> MsGuns © (23.05.08 00:38) [3]
Как передать данные в поток? ссылку например на форму -
dreamse (23.05.08 01:27) [5]Решил. Спасибо всем.
создал отдельный поток, отдельным модулем:
type
PingThead = class(TThread)
private
PingText:string;
FForm: TForm;
procedure Setform(const Value: TForm);
public
protected
procedure Execute; override;
procedure UpdateCaption;
published
property form: TForm read Fform write Setform;
end;
При создании потока передаю ссылку на форму MDI
StartPing := PingThead.Create(true);
StartPing.form := Self;
StartPing.Priority := tpLowest;
StartPing.Resume;
и затем при синхронизации в потоке:
procedure PingThead.UpdateCaption;
begin
TFrmPing(FForm).Mem_ping_result.Text := pingText;
end;
Всем большое спасибо. -
Параметры потоку лучше передавать в его конструкторе. Избавит от необходимости разделять процедуры создания и пуска
-
пример
форма с потокомunit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm2 = class;
TPingThread = class(TThread)
private
FForm: TForm2; //это не обьект внутри потока, а всего лиш ссылка на форму из основного,
//т.е. обращение только через синхронизацию!!!
i: integer;
procedure DoAnything;
public
constructor Create(CreateSuspended: Boolean; Form: TForm2);
procedure Execute; override;
end;
TForm2 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
PingThread: TPingThread;
public
end;
implementation
{$R *.dfm}
constructor TPingThread.Create(CreateSuspended: Boolean; Form: TForm2);
begin
inherited Create(CreateSuspended);
FForm:= Form;
i:= 0;
end;
procedure TPingThread.DoAnything;
begin
FForm.Memo1.Lines.Add(IntTostr(i));
Inc(i);
end;
procedure TPingThread.Execute;
begin
while not terminated do begin
Sleep(3000);
Synchronize(DoAnything);
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
PingThread:= TPingThread.Create(false, self);
PingThread.FreeOnTerminate:= true;
end;
procedure TForm2.FormDestroy(Sender: TObject);
begin
PingThread.Terminate;
end;
end.
вызов (создание mdi чилда)procedure TForm1.Button1Click(Sender: TObject);
begin
TForm2.Create(self);
end; -
И еще. "Правильный" поток не обязан знать ни о каких там формах или других внешних объектах. Все, что ему нужно, передавать исключительно параметрами. Это избавит поток от объектозависимости и предотвратит массу глюков
-
dreamse (23.05.08 08:32) [9]Спасибо. Записал пример. Буду иметь ввиду.
-
При использовании приведенного примера надо быть особенно осторожным - форма постоянно находится в асинхроне по сравнению с основным потоком. ИМХО, такие формы нужны, но лишь при определенной специфике всего приложения.
-
Блин, кусок "по сравнению" надо выбросить - он там лишний.