用了一个线程控件(SimpleThread),当线程Excute时动态加载一个窗体
运行时提示错误:
project Test_AT.exe raised exception class EInvalidOperation with message 'Canvans does not allow drawing',process stopped.use step or run to continue如果不在线程中加载这个窗体是正常的。哪位大侠能帮我看看,怎么回事?相关代码如下function TForm_main.Test_dialog(title: string): boolean;
var
flag:boolean;
begin
with TForm_TestDialog.Create(application) do begin
try
showmodal;
finally
if modalresult=mryes then begin
flag:=true;
end else begin
flag:=false;
end;
free;
end; end;
result:=flag;
end;procedure TForm_main.SimpleThread1Execute(Sender: TObject);
begin
Test_Dialog('sdfsf');
end;
看起来好象没有得到加载窗体的句柄,急死我了,我该怎样解决?高手们给点意见吧!function TForm_main.Test_dialog(title: string): boolean;
var
flag:boolean;
begin
hide;
with TForm_TestDialog.Create(application) do begin
try
showmodal;
finally
if modalresult=mryes then begin
flag:=true;
end else begin
flag:=false;
end;
free;
end; end;
show;
result:=flag;
end;
procedure TForm_main.go;
begin
Test_Dialog('sdfsf');
end;
procedure TForm_main.SimpleThread1Execute(Sender: TObject);
begin
Synchronize(go);
end;
这个错误提示就是说,两个线程同时访问Canvas对象而没有同步,换句话说,在DELPHI里,任意时刻只能有一个线程能访问Canvas,这是由画布对象的特性决定了的(参见LOCK),所以DELPHI的TTHREAD对象提供一个Synchronize方法来让线程暂时切换到主线程里去。如果你的这个TSimpleThread也是从Thread继承下来的,不可能没有这个方法。
简单地说,凡涉及到“非线程安全”的操作,都要同步,而DELPHI的一切可视操作,比方说对画布的绘制,对控件的重绘,都是“非线程安全”的。
请问我该如何从 TThread 继承 Synchronize 方法?
谢谢!unit SimpleThread;interface
uses
Windows, SysUtils, Classes;type EThreadError = class( Exception ); TSimpleThread = class( TComponent )
private
FTerminated :Boolean;
FHandle :THandle;
FThreadID :THandle;
FPriority :TThreadPriority;
FActive :Boolean;
FSuspended :Boolean;
FOnExecute :TNotifyEvent;
FOnActivate :TNotifyEvent;
FOnTerminate :TNotifyEvent;
FOnSuspend :TNotifyEvent;
FOnResume :TNotifyEvent;
procedure UpdateThreadPriority;
procedure SetSuspended( NewState :Boolean );
procedure SetActive( NewState :Boolean );
procedure SetPriority( NewPriority :TThreadPriority );
protected
procedure Loaded; override;
procedure Activate; virtual;
procedure Terminate; virtual;
procedure Suspend; virtual;
procedure Resume; virtual;
procedure Execute; virtual;
procedure DoActivate;
procedure DoTerminate;
procedure DoSuspend;
procedure DoResume;
public
constructor Create( anOwner :TComponent ); override;
destructor Destroy; override;
procedure Kill;
property Handle :THandle
read FHandle;
property ThreadID :THandle
read FThreadID;
property Terminated :Boolean read FTerminated;
published
property Priority :TThreadPriority
read FPriority write SetPriority;
property Active :Boolean
read FActive write SetActive;
property Suspended :Boolean
read FSuspended write SetSuspended;
property OnExecute :TnotifyEvent
read FOnExecute write FOnExecute;
property OnActivate :TNotifyEvent
read FOnActivate write FOnActivate;
property OnTerminate :TNotifyEvent
read FOnTerminate write FOnTerminate;
property OnSuspend :TNotifyEVent
read FOnSuspend write FOnSuspend;
property OnResume :TNotifyEvent
read FOnResume write FOnResume;
end;procedure Register;implementationprocedure Register;
begin
RegisterComponents( 'more...', [ TSimpleThread ] );
end;
procedure ThreadProc( Self :TSimpleThread ); stdcall;
begin
with Self do
begin
Activate;
Execute;
Terminate;
end;
end;
{ TSimpleThread }procedure TSimpleThread.Activate;
begin
if assigned( FOnActivate ) then FOnActivate( Self );
end;procedure TSimpleThread.Terminate;
begin
if assigned( FOnTerminate ) then FOnTerminate( Self );
end;procedure TSimpleThread.Suspend;
begin
if assigned( FOnSuspend ) then FOnSuspend( Self );
end;procedure TSimpleThread.Resume;
begin
if assigned( FOnResume ) then FOnResume( Self );
end;procedure TSimpleThread.Execute;
begin
if Assigned( FOnExecute ) then FOnExecute( Self );
end;constructor TSimpleThread.Create( anOwner :TComponent );
begin
inherited Create( anOwner );
FPriority := tpNormal;
FHandle := 0;
FTerminated := false;
FActive := false;
FSuspended := false;
end;destructor TSimpleThread.Destroy;
begin
Active := false;
inherited;
end;procedure TSimpleThread.DoActivate;
var F :Longint;
begin
F := 0;
if ( FSuspended ) then F := F OR CREATE_SUSPENDED;
FHandle := CreateThread( nil, 0, @ThreadProc,
Pointer( Self ), F, FThreadID );
if ( FHandle = 0 ) then raise EThreadError.Create( 'Error creating thread' );
FActive := true;
end;procedure TSimpleThread.DoTerminate;
begin
if ( FHandle = 0 ) then exit;
if Active and ( not Suspended ) then
begin
FTerminated := true;
WaitForSingleObject( FHandle, INFINITE );
FActive := false;
FTerminated := false;
end;
if ( FHandle <> 0 ) then CloseHandle( FHandle );
FHandle := 0;
FThreadID := 0;
end;procedure TSimpleThread.DoSuspend;
begin
FSuspended := true;
SuspendThread( FHandle );
Suspend;
end;procedure TSimpleThread.DoResume;
begin
if ResumeThread(FHandle) = 1 then
begin
FSuspended := False;
Resume;
end;
end;
procedure TSimpleThread.Kill;
begin
if ( FHandle = 0 ) then exit;
TerminateThread( FHandle, 0 );
FHandle := 0;
FThreadID := 0;
FActive := false;
Terminate;
end;const
Priorities: array [TThreadPriority] of Integer =
(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,
THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL,
THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL);procedure TSimpleThread.UpdateThreadPriority;
begin
SetThreadPriority(FHandle, Priorities[ FPriority ] );
end;procedure TSimpleThread.SetSuspended( NewState :Boolean );
begin
if ( Suspended xor NewState ) then
if FHandle = 0
then FSuspended := NewState
else if NewState then DOSuspend else DoResume;
end;procedure TSimpleThread.SetActive( NewState :Boolean );
begin
if ( csLoading in COmponentState ) or ( csDesigning in COmponentState )
then begin
FActive := NewState;
exit;
end;
if ( Active xor NewState ) then
if NewState
then DoActivate
else DoTerminate;
end;procedure TSimpleThread.SetPriority( NewPriority :TThreadPriority );
begin
FPriority := NewPriority;
if FHandle <> 0 then UpdateThreadPriority;
end;procedure TSimpleThread.Loaded;
begin
inherited;
if not ( csDesigning in COmponentState ) then
if Active then DoActivate;
end;
end.