Question

I have a project that main Form is created after my Thread. But this code don't work correctly:

type
  TMyThread = class(TThread)
  public
    procedure Execute; override;
    procedure doProc;
  end; { type }
.
.
.
procedure TForm1.FormCreate(Sender: TObject);
var
  thrd : TMyThread;
begin
  thrd := TMyThread.Create(True);
  thrd.Resume;

  // Following code will cause the `Form` to show the time delay is about 5 seconds...
end;
.
.
.

procedure TMyThread.Execute;
begin
  inherited;

  doProc;
end;

procedure TMyThread.doProc;
var
  AForm : TForm;
begin
  AForm := TForm.Create(nil);
  AForm.Caption := 'Thread Form';
  AForm.Position := poScreenCenter;
  AForm.FormStyle := fsStayOnTop;
  AForm.Show;
end;

I don't want to use Synchronize. Is there a way to run my Thread out of main Form? I want to show a Form before the main Form begin to create while the main Form is shown.

Was it helpful?

Solution 6

unit AniThread;

interface 

uses 
  Classes, Windows, Controls, Graphics; 

type 
  TAnimationThread = class(TThread) 
  private 
    { private declarations } 
    FWnd: HWND; 
    FPaintRect: TRect; 
    FbkColor, FfgColor: TColor; 
    FInterval: integer; 
  protected 
    procedure Execute; override; 
  public 
    constructor Create(paintsurface : TWinControl; {Control to paint on } 
      paintrect : TRect;          { area for animation bar }
      bkColor, barcolor : TColor; { colors to use }
      interval : integer);        { wait in msecs between paints}
  end; 

implementation 

constructor TAnimationThread.Create(paintsurface : TWinControl; 
  paintrect : TRect; bkColor, barcolor : TColor; interval : integer); 
begin 
  inherited Create(True); 
  FWnd := paintsurface.Handle; 
  FPaintRect := paintrect; 
  FbkColor := bkColor; 
  FfgColor := barColor; 
  FInterval := interval; 
  FreeOnterminate := True; 
  Resume; 
end; { TAnimationThread.Create } 

procedure TAnimationThread.Execute; 
var 
  image : TBitmap; 
  DC : HDC; 
  left, right : integer; 
  increment : integer; 
  imagerect : TRect; 
  state : (incRight, incLeft, decLeft, decRight); 
begin 
  Image := TBitmap.Create; 
  try 
    with Image do  
    begin 
      Width := FPaintRect.Right - FPaintRect.Left; 
      Height := FPaintRect.Bottom - FPaintRect.Top; 
      imagerect := Rect(0, 0, Width, Height); 
    end; { with } 
    left := 0; 
    right := 0; 
    increment := imagerect.right div 50; 
    state := Low(State); 
    while not Terminated do  
    begin 
      with Image.Canvas do  
      begin 
        Brush.Color := FbkColor; 
        FillRect(imagerect); 
        case state of 
          incRight:  
          begin 
            Inc(right, increment); 
            if right > imagerect.right then  
            begin 
              right := imagerect.right; 
              Inc(state); 
            end; { if } 
          end; { case incRight } 
          incLeft:  
          begin 
            Inc(left, increment); 
            if left >= right then  
            begin 
              left := right; 
              Inc(state); 
            end; { if } 
          end; { case incLeft } 
          decLeft:  
          begin 
            Dec(left, increment); 
            if left <= 0 then  
            begin 
              left := 0; 
              Inc(state); 
            end; { if } 
          end; { case decLeft } 
          decRight:  
          begin 
            Dec(right, increment); 
            if right <= 0 then  
            begin 
              right := 0; 
              state := incRight; 
            end; { if } 
          end; { case decLeft } 
        end; { case } 
        Brush.Color := FfgColor; 
        FillRect(Rect(left, imagerect.top, right, imagerect.bottom)); 
      end; { with } 
      DC := GetDC(FWnd); 
      if DC <> 0 then 
        try 
          BitBlt(DC, 
            FPaintRect.Left, 
            FPaintRect.Top, 
            imagerect.right, 
            imagerect.bottom, 
            Image.Canvas.handle, 
            0, 0, 
            SRCCOPY); 
        finally 
          ReleaseDC(FWnd, DC); 
        end; 
      Sleep(FInterval); 
    end; { while } 
  finally 
    Image.Free; 
  end; 
  InvalidateRect(FWnd, nil, True); 
end; { TAnimationThread.Execute } 

end. 

//============================ HOW to USE IT ============================
{
 Usage: 
 Place a TPanel on a form, size it as appropriate.Create an instance of the 
 TanimationThread call like this: procedure TForm1.Button1Click(Sender : TObject); } 
var 
  ani : TAnimationThread; 
  r : TRect; 
begin
  r := Panel1.ClientRect;
  InflateRect(r, - Panel1.BevelWidth, - Panel1.BevelWidth);
  ani := TAnimationThread.Create(Panel1, r, Panel1.color, clBlue, 25);
  Button1.Enabled := False; 
  Application.ProcessMessages; 
  Sleep(30000);  // replace with query.Open or such 
  Button1.Enabled := True; 
  ani.Terminate; 
  ShowMessage('Done'); 
end.

OTHER TIPS

Mohammad, I think here is a classic example of total [multithreading] misunderstanding.

It is always good that you experiment with your code, but you must learn the basics. As David said, you are breaking the rules. The whole concept. You might be a thousand times frustrated because you code does not work, but VCL will not suddenly become thread-safe because of your frustrations.

My suggestion would be to RTFM. There is an excellent one.

A book by Martin Harvey, Multithreading - The Delphi Way. The reading is easy and fun for real geeks. You may not want to go beyond mutexes, critical sections and concurrency control, but at least you will learn some really important concepts about the amazing world of multithreading.

Please do not expect anyone here at SO to answer the wrong questions. The most of the responders are professional and experienced programmers and they wouldn't wanna waste their time to dive into the discussions which are initially wrong. People here are quite boolean ;)

In other words, try to learn some very basic things before you post your questions.

Your code breaks VCL threading rules. All VCL access must be on the main thread.

If you want to show GUI in a different thread (and very seldom is that a good idea) you need to use raw Win32 API calls. And run a message loop in the thread.

I cannot tell you how to solve your problem because I don't know what your problem is. But if all you want to do is show a form before the main form, just do that. No obvious need for a thread.

it may be way too obvious but why dont you just run your code before the Form is created? (the others already suggested something like that) if you create a new project and look at the source code of the project it will look like that:

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

begin
  (* Insert your code in here so it runs before the mainform is created *) 

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

Sorry, if i misunderstood your problem.

In answer to the question "why is my thread run after form creation?" in TCustomForm.Create, DoCreate is called, which fires the OnCreate event. At that point the form itself is already created and will be shown right after the OnCreate event returns.

In your case, you create the thread during this event. Calling Resume only tells the thread that it can execute, but is does not guarantee immediate execution (plus it will have issues, as David explained). It is likely the DoCreate will finish before the Execute method is called. This also means that Synchronize will not help, as that would be called from within the Execute context.

If you want to be certain that another form is first shown, you can do several things:

  1. Make the other form your main form and show your current main form when it closes (or a button is clicked, a timer runs out, etc)
  2. Put the code to display the other form in the BeforeDestruction method to have it execute before the constructor of the form. This will make it show first, but it will not prevent the main form from showing right after.

I hope this helps you.

QUESTIONS:

(1) Is there a way to run my Thread out of main Form?

(2) I want to show a Form before the main Form begin to create ...

(3) ...while the main Form is shown.

RESPONSES:

(1) Yes. Do the creation of thread out of the Main form (not inside the Oncreate event of Main form).

(2) OK. (same responde of (1)). Do the form creation (or Thread) before create the Main form (not in OnCreate event of Main Form).

(3) This is not possible with (1) and (2). Sorry.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top