Конференция "Основная" » работа с потоками в MDI [D7, WinXP]
 
  • 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;
  • MsGuns © (23.05.08 00:34) [2]
    не советую привязывть треды ни к МДИ, ни к каким другим формам. Поток как класс создай вне всяких форм, а уже из форм надо его создавать, запускать и прибивать. Для отображения хода процессов использовать некую общую (например в гл.форме) процедуру, которую вызывать из потоков с использованием Synchronize. Если для отображения надо использовать много параметров разных типов, то использовать дескрипторы, которые надо создавать и инициализировать перед созданием потока, а указатель на него передавать в конструктор потока, как переменную того же типа, что и дескриптор. Ессно, эту переменную надо уложить в поле класса потока. По завершению потока дескриптор должен прибиваться.
  • MsGuns © (23.05.08 00:38) [3]
    Перед синхрон-вызовом "отображающей" процедуры поток должен записать в дескриптор данные о текущем статусе или чего там надо показывать и передать ей указатель на "свой" дескриптор.
    Либо вообще ничего не вызывать, а в самой отображающей форме через определенные интервалы времени просматривать список дескрипторв потоков, обновляя соответствующие визуальые контролы (например, сетки или листвью)
  • 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;



    Всем большое спасибо.
  • MsGuns © (23.05.08 01:57) [6]
    Параметры потоку лучше передавать в его конструкторе. Избавит от необходимости разделять процедуры создания и пуска
  • sniknik © (23.05.08 02:00) [7]
    пример
    форма с потоком
    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;

  • MsGuns © (23.05.08 02:02) [8]
    И еще. "Правильный" поток не обязан знать ни о каких там формах или других внешних объектах. Все, что ему нужно, передавать исключительно параметрами. Это избавит поток от объектозависимости и предотвратит массу глюков
  • dreamse (23.05.08 08:32) [9]
    Спасибо. Записал пример. Буду иметь ввиду.
  • MsGuns © (23.05.08 12:53) [10]
    При использовании приведенного примера надо быть особенно осторожным - форма постоянно находится в асинхроне по сравнению с основным потоком. ИМХО, такие формы нужны, но лишь при определенной специфике всего приложения.
  • MsGuns © (23.05.08 12:55) [11]
    Блин, кусок "по сравнению" надо выбросить - он там лишний.
 
Конференция "Основная" » работа с потоками в MDI [D7, WinXP]
Есть новые Нет новых   [134491   +8][b:0][p:0.002]