2
votes

Good afternoon :-), I have one Frame. This Frame I dynamically created by Main Form.

Main form:

Interface := TInterface.Create(self);
    with handlingInterface do begin
      Parent := Form1;
      Left := 0; Top := 35;
      Width := 570; Height := 250;
    end;

In Frame I have a Thread. I call this Thread from Frame. Why I can synchronize Thread with Frame? There isn't any:

var
Form1: TForm1;

I call Thread inside Frame and I want to change Position of ProgressBar in Frame. I don't know, why I can in Synchronize method of Thread access the ProgressBar.

If would be Thread and ProgressBar in Form - Synchronize access is Form1.ProgressBar ...

But I have Thread and ProgressBar in Frame.

2
@Nanik: what do you mean my synchronize in this case? What exactly needs synchronization? If you use the respective member function of TThread you will already get what you want, because that effectively runs the respective code in the main thread instead of the TThread-derived instance. - 0xC0000022L
Thanks to comment, I edit post. - Nanik
Unit1.Form1.ProgressBar, put 'Unit1' in the uses clause of the implementation section of the thread unit. Or, is it a long shot? - Sertac Akyuz
Thanks :-), but ProgressBar is on Frame, this is a problem. - Nanik
You can give a reference of your frame to the thread when you create the thread and use that when you need to update the progress bar. - Mikael Eriksson

2 Answers

9
votes

If the only thing you're trying to do is update the progress bar from the thread, there is a lighter weight option. I would consider using PostMessage instead. You don't want your thread to know too much about the details of the frame anyway.

When you create the thread, give it the handle of your frame so it knows where to post the message. Have the frame listen for the Windows message, which includes the progress position, and update the progress bar.

Here is a very simple example that increments the progress bar from 0 to 100 with a short sleep between each increment:

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;

const
  WM_PROGRESS_MESSAGE = WM_USER + 99;

type
  TProgressThread = class(TThread)
  private
    FWindowHandle: HWND;
  protected
    procedure Execute; override;
  public
    property WindowHandle: HWND read FWindowHandle write FWindowHandle;
  end;

  TFrame2 = class(TFrame)
    ProgressBar1: TProgressBar;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure OnProgressMessage(var Msg: TMessage); message WM_PROGRESS_MESSAGE;
  public
  end;

implementation

{$R *.dfm}

{ TFrame2 }

procedure TFrame2.Button1Click(Sender: TObject);
var
  lThread: TProgressThread;
begin
  lThread := TProgressThread.Create(True);
  lThread.FreeOnTerminate := True;
  lThread.WindowHandle := Self.Handle;
  lThread.Start;
end;

procedure TFrame2.OnProgressMessage(var Msg: TMessage);
begin
  ProgressBar1.Position := Msg.WParam;
end;


{ TProgressThread }

procedure TProgressThread.Execute;
var
  lProgressCount: Integer;
begin
  inherited;

  for lProgressCount := 0 to 100 do
  begin
    PostMessage(FWindowHandle, WM_PROGRESS_MESSAGE, lProgressCount, 0);
    Sleep(15);
  end;
end;

end.
2
votes

You can give a reference to your progress bar to the thread.

Sample thread class.

unit Unit6;

interface

uses
    Classes, ComCtrls;

type
    TProgressBarThread = class(TThread)
    private
        { Private declarations }
        FProgressBar: TProgressBar;
        procedure MoveProgress;
    protected
        procedure Execute; override;
    public
        procedure SetProgressBar(ProgressBar: TProgressBar);
    end;

implementation

{ ProgressBarThread }
procedure TProgressBarThread.Execute;
begin
    { Place thread code here }
    Synchronize(MoveProgress);

end;

procedure TProgressBarThread.MoveProgress;
begin
    FProgressBar.StepIt;
end;

procedure TProgressBarThread.SetProgressBar(ProgressBar: TProgressBar);
begin
    FProgressBar := ProgressBar;
end;

end.

Use like this

var
    PBT: TProgressBarThread;
begin
    PBT := TProgressBarThread.Create(True);
    PBT.FreeOnTerminate := True;
    PBT.SetProgressBar(ProgressBar1);
    PBT.Start;
//  PBT.Resume;
end;