我有一个项目,主Form
是在Thread
之后创建的。
但是这段代码无法正常工作:
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;
我不想使用Synchronize
。
有没有办法从主Thread
中运行我的Form
?
我希望在主Form
开始创建之前显示Form
,同时显示主Form
。
答案 0 :(得分:5)
穆罕默德,我认为这是总 [多线程] 误解的典型例子。
您尝试使用代码总是好的,但您必须学习基础知识。 正如大卫所说,你违反了规则。整个概念。您可能会因为代码不起作用而感到沮丧,但由于您的挫败感,VCL将 突然变为线程安全。
我的建议是RTFM。有一个很棒的。
Martin Harvey的一本书,Multithreading - The Delphi Way。对于真正的极客来说,阅读既简单又有趣。您可能不想超越互斥体,关键部分和并发控制,但至少您将学习一些关于多线程惊人世界的重要概念。
请不要指望SO的任何人回答错误的问题。大多数响应者都是专业且经验丰富的程序员,他们不想浪费时间潜入最初错误的讨论中。这里的人很布尔;)
换句话说,在发布问题之前,尝试学习一些非常基本的东西。
答案 1 :(得分:3)
您的代码违反了VCL线程规则。所有VCL访问必须在主线程上。
如果要在不同的线程中显示GUI(很少这是一个好主意),您需要使用原始的Win32 API调用。并在线程中运行消息循环。
我不能告诉你如何解决你的问题,因为我不知道你的问题是什么。但是,如果你想要做的就是在主表单之前显示一个表单,那就去做吧。没有明显需要一个线程。
答案 2 :(得分:2)
它可能太明显了,但为什么不在表单创建之前运行代码? (其他人已经提出类似的建议) 如果您创建一个新项目并查看项目的源代码,它将如下所示:
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.
很抱歉,如果我误解了你的问题。
答案 3 :(得分:1)
回答问题" 为什么我的线程在表单创建后运行?"
在TCustomForm.Create
中调用DoCreate
,它会触发OnCreate
事件。
此时表单本身已经创建,并将在OnCreate
事件返回后立即显示。
在您的情况下,您在此事件期间创建线程。
调用Resume
只告诉线程它可以执行,但不保证立即执行(加上它会有问题,正如David解释的那样)。调用DoCreate
方法之前,Execute
可能会完成。
这也意味着Synchronize
将无法提供帮助,因为这将在Execute上下文中调用。
如果您想确定首次显示另一个表单,您可以执行以下操作:
BeforeDestruction
方法中显示另一个表单,以使其在表单的构造函数之前执行。这将使它首先显示,但它不会阻止主窗体在其后显示。我希望这会对你有所帮助。
答案 4 :(得分:0)
问题:
(1)有没有办法从主窗体中运行我的线程?
(2)我想在主表单开始创建之前显示一个表单...
(3)......显示主要表格时。
<强>反应:强>
(1)是的。从Main表单创建线程(不在Main表单的Oncreate事件中)。
(2)好的。 (同等回应(1))。在创建Main表单之前进行表单创建(或Thread)(而不是在Main Form的OnCreate事件中)。
(3)这对于(1)和(2)是不可能的。抱歉。
答案 5 :(得分:-2)
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.