Criar um Form na thread
Olá pessoal,
Estou com um problema trabalhando com threads.
Tenho uma thread que faz um processamento demorado e lento e durante este processamento, gostaria de criar um Form e exibi-lo na tela durante este processamento e destruí-lo no final.
Queria que este form fosse criado diretamente pela Thread, mas quando o form é criado, recebo uma mensagem dizendo: ´[b:c6d681f311]Canvas does not allow drawing[/b:c6d681f311]´.
Esta mensagem só aparece quando executo o programa fora do Delphi. Quando executo dentro do delphi ela não aparece. Alguém poderia me ajudar a resolver este problema?
Estou colando abaixo o código da thread. Ele é bem simples.
Muito obrigado pela atenção.
Estou com um problema trabalhando com threads.
Tenho uma thread que faz um processamento demorado e lento e durante este processamento, gostaria de criar um Form e exibi-lo na tela durante este processamento e destruí-lo no final.
Queria que este form fosse criado diretamente pela Thread, mas quando o form é criado, recebo uma mensagem dizendo: ´[b:c6d681f311]Canvas does not allow drawing[/b:c6d681f311]´.
Esta mensagem só aparece quando executo o programa fora do Delphi. Quando executo dentro do delphi ela não aparece. Alguém poderia me ajudar a resolver este problema?
Estou colando abaixo o código da thread. Ele é bem simples.
type
TThreadExemplo = class(TThread)
private
Obj : TObjqualquer;
Form : TForm1;
protected
procedure Execute; override;
public
Constructor Criar;
end;
implementation
{ TThreadExemplo }
constructor TThreadExemplo.Criar;
begin
inherited create(true);
Priority := tpLowest;
Obj := TObjqualquer.create;
end;
procedure TThreadExemplo.Execute;
var erro : string;
begin
try
Form := TForm1.Create(nil);
try
Form.Show;
Obj.processamentoqualquer(erro);
finally
Form.Close;
FreeAndNil(Form);
FreeAndNil(Obj);
end;
except
on e : exception do
application.MessageBox(pchar(e.Message),´erro´,MB_OK);
end;
end;
Muito obrigado pela atenção.
Prgdelphi
Curtidas 0
Mais Respostas
Bruno Belchior
05/09/2005
não sou um exímio especialista em Thread´s porém acho q c vc deveria criar o contructor com o nome [b:5cd1938427]Create[/b:5cd1938427] em vez de [b:5cd1938427]Criar[/b:5cd1938427]...
GOSTEI 0
Massuda
05/09/2005
...gostaria de criar um Form e exibi-lo na tela durante este processamento...
Para poder usar um elemento visual numa thread, você precisa fazer isso dentro de um procedimento chamado via [b:cd6481cba9]TThread.Synchronize[/b:cd6481cba9]; isso inclui criar, mostrar, atualizar e destruir o form. O mesmo vale para operações que envolvam banco de dados.GOSTEI 0
Bruno Belchior
05/09/2005
então o [b:9a2697da85]TThread.Synchronize[/b:9a2697da85] seria uma espécie de ´porta de comunicação´ com o mundo externo à Thread :?:
GOSTEI 0
Massuda
05/09/2005
[quote:9ab162fcfe=´Bruno Belchior´]...seria uma espécie de ´porta de comunicação´ com o mundo externo à Thread ?[/quote:9ab162fcfe]Na verdade é um modo de sincronizar sua thread com a thread principal do programa.
Todo programa tem pelo menos uma thread (a thread principal). No caso da parte visual (o que inclui praticamente todo o código da VCL), ela é executada dentro da thread principal. O código da VCL não é [i:9ab162fcfe]thread safe[/i:9ab162fcfe] (ou seja, não pode ser executado em ambiente multi-thread) então a solução adotada foi possibilitar sincronizar qualquer thread com a thread principal.
Quando você executa TThread.Synchronize, sua thread encaixa na fila de mensagens da thread principal um pedido para ela executar o procedimento sincronizado (o que você passou para TThread.Synchronize). Isso garante que você consegue criar um form na sua thread num momento que a thread principal não esteja fazendo o mesmo, o que poderia, por exemplo, corromper a variável Screen.
Todo programa tem pelo menos uma thread (a thread principal). No caso da parte visual (o que inclui praticamente todo o código da VCL), ela é executada dentro da thread principal. O código da VCL não é [i:9ab162fcfe]thread safe[/i:9ab162fcfe] (ou seja, não pode ser executado em ambiente multi-thread) então a solução adotada foi possibilitar sincronizar qualquer thread com a thread principal.
Quando você executa TThread.Synchronize, sua thread encaixa na fila de mensagens da thread principal um pedido para ela executar o procedimento sincronizado (o que você passou para TThread.Synchronize). Isso garante que você consegue criar um form na sua thread num momento que a thread principal não esteja fazendo o mesmo, o que poderia, por exemplo, corromper a variável Screen.
GOSTEI 0
Mmoreira
05/09/2005
Massuda,
Estou fazendo um sistema para fazer download de um arquivo em um FTP ultilizando IdFtp ( Indy 10 ). Estou usando uma Thread para que meu sistema nao fique congelado enquanto o arquivo é baixado. Nao tenho muita ou quase nenhuma experiencia com TThread ... Fiz esta com algumas dicas que peguei aqui no forum ...
Voce poderia dar uma olhada e me dizer o que nao esta certo e onde eu posso melhorar ... Outra coisa tambem queria criar uma rotina para cancelar o download ...
Vc pode me dar uma ajuda ...
valewss
Estou fazendo um sistema para fazer download de um arquivo em um FTP ultilizando IdFtp ( Indy 10 ). Estou usando uma Thread para que meu sistema nao fique congelado enquanto o arquivo é baixado. Nao tenho muita ou quase nenhuma experiencia com TThread ... Fiz esta com algumas dicas que peguei aqui no forum ...
Voce poderia dar uma olhada e me dizer o que nao esta certo e onde eu posso melhorar ... Outra coisa tambem queria criar uma rotina para cancelar o download ...
unit ufmPrincipal;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdFtp, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, IdExplicitTLSClientServerBase, ComCtrls;
type
Thread_Baixa_Arquivo = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
type
TfmPrincipal = class(TForm)
btnBaixar: TButton;
ProgressBar: TProgressBar;
IdFTP1: TIdFTP;
Label1: TLabel;
btnCancelar: TButton;
procedure btnBaixarClick(Sender: TObject);
procedure IdFTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode;
AWorkCountMax: Integer);
procedure IdFTP1Work(ASender: TObject; AWorkMode: TWorkMode;
AWorkCount: Integer);
procedure IdFTP1WorkEnd(ASender: TObject; AWorkMode: TWorkMode);
procedure btnCancelarClick(Sender: TObject);
private
Baixa_Arquivo : Thread_Baixa_Arquivo;
{ Private declarations }
public
{ Public declarations }
end;
var
fmPrincipal: TfmPrincipal;
implementation
{$R *.dfm}
procedure TfmPrincipal.btnBaixarClick(Sender: TObject);
begin
if Baixa_Arquivo = nil then begin
Baixa_Arquivo := Thread_Baixa_Arquivo.Create(true);
Baixa_Arquivo.Resume;
end else begin
ShowMessage( ´Em execução!´ );
end;
end;
procedure TfmPrincipal.IdFTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Integer);
begin
ProgressBar.Position := 0;
ProgressBar.Max := AWorkCountMax; // 2507222
end;
procedure TfmPrincipal.IdFTP1Work(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Integer);
begin
Application.ProcessMessages;
ProgressBar.Position := AWorkCount;
Label1.Caption := IntToStr( AWorkCount );
Update;
end;
{ Thread_Baixa_Arquivo }
procedure Thread_Baixa_Arquivo.Execute;
begin
fmPrincipal.IdFTP1.Host := ´www.meudominio.com.br´;
fmPrincipal.IdFTP1.Username := ´logon´;
fmPrincipal.IdFTP1.Password := ´senha´;
fmPrincipal.IdFTP1.Connect;
try
fmPrincipal.IdFTP1.ChangeDir(´diretorio/´);
fmPrincipal.IdFTP1.Get(´arquivo.zip´,´c:\arquivo.zip´,true);
finally
fmPrincipal.IdFTP1.Disconnect;
FreeAndNil( fmPrincipal.Baixa_Arquivo );
end;
end;
procedure TfmPrincipal.IdFTP1WorkEnd(ASender: TObject; AWorkMode: TWorkMode);
begin
ProgressBar.Position := 0;
Label1.Caption := ´0´;
end;
procedure TfmPrincipal.btnCancelarClick(Sender: TObject);
begin
// fazer cancelamento do download -----
end;
end.
Vc pode me dar uma ajuda ...
valewss
GOSTEI 0