用了一个线程控件(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;

解决方案 »

  1.   

    如果在动态加载窗体前,先用 hide 将主窗体隐藏,则可以正常运行
    看起来好象没有得到加载窗体的句柄,急死我了,我该怎样解决?高手们给点意见吧!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;
      

  2.   

    同步调用显示窗体
    procedure TForm_main.go;
    begin
        Test_Dialog('sdfsf');
    end;
    procedure TForm_main.SimpleThread1Execute(Sender: TObject);
    begin
        Synchronize(go);
    end;
      

  3.   

    回:hkbarton(宁静至远)(西南交大) 我用的不是delphi 的TThread,而是网上下载的TSimpleThread 控件,所以没有Synchronize方法还有其他办法吗?谢谢!
      

  4.   

    宁静至远的意见是正确的。
    这个错误提示就是说,两个线程同时访问Canvas对象而没有同步,换句话说,在DELPHI里,任意时刻只能有一个线程能访问Canvas,这是由画布对象的特性决定了的(参见LOCK),所以DELPHI的TTHREAD对象提供一个Synchronize方法来让线程暂时切换到主线程里去。如果你的这个TSimpleThread也是从Thread继承下来的,不可能没有这个方法。
    简单地说,凡涉及到“非线程安全”的操作,都要同步,而DELPHI的一切可视操作,比方说对画布的绘制,对控件的重绘,都是“非线程安全”的。
      

  5.   

    以下是TSimpleThread内容 
    请问我该如何从 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.