![]() |
Sincronizar Threads e Interface Gráfica |
Índice
Introdução
Nesse post iremos ver como funciona a Sincronização de Threads com a Interface Gráfica em Delphi.
A programação com threads é uma prática comum para executar tarefas em segundo plano sem bloquear a interface do usuário. No entanto, atualizar a interface gráfica a partir de uma thread pode ser um desafio. Este artigo aborda como sincronizar threads com a interface gráfica em Delphi, utilizando TThread.Synchronize
e TThread.Queue
.
O que são Threads?
Threads são fluxos de execução independentes que podem executar tarefas simultaneamente dentro de uma aplicação. Em Delphi, a classe TThread
é usada para criar e gerenciar threads. Threads são úteis para tarefas que demoram a ser concluídas, como operações de E/S, cálculos intensivos e acesso a banco de dados.
Problema com a Atualização da Interface Gráfica
A interface gráfica de uma aplicação Delphi (VCL) não é thread-safe, o que significa que acessar ou modificar componentes visuais diretamente de uma thread pode causar comportamentos inesperados ou falhas. Para evitar isso, devemos sincronizar o acesso à interface gráfica.
TThread.Synchronize
TThread.Synchronize
é um método que permite executar um código no contexto do thread principal, garantindo que o acesso à interface gráfica seja seguro. O código passado para Synchronize
é executado de forma síncrona, ou seja, a thread secundária espera até que o código termine de executar no thread principal.
type
TMyThread = class(TThread)
protected
procedure Execute; override;
procedure UpdateUI;
end;
procedure TMyThread.Execute;
begin
// Código que a thread executa em segundo plano
// ...
Synchronize(UpdateUI);
end;
procedure TMyThread.UpdateUI;
begin
// Código para atualizar a interface gráfica
Form1.Label1.Caption := 'Thread terminou a execução';
end;
No exemplo acima, UpdateUI
é um método que atualiza um componente de interface gráfica. Synchronize
garante que UpdateUI
seja executado no contexto do thread principal.
TThread.Queue
TThread.Queue
é semelhante a Synchronize
, mas a execução do código passado é enfileirada e ocorre de forma assíncrona. Isso significa que a thread secundária não precisa esperar o término da execução no thread principal.
type
TMyThread = class(TThread)
protected
procedure Execute; override;
procedure QueueUIUpdate;
end;
procedure TMyThread.Execute;
begin
// Código que a thread executa em segundo plano
// ...
Queue(QueueUIUpdate);
end;
procedure TMyThread.QueueUIUpdate;
begin
// Código para atualizar a interface gráfica
Form1.Label1.Caption := 'Thread terminou a execução (assíncrono)';
end;
Quando usar Synchronize e Queue?
- Synchronize: Use quando a thread secundária precisa esperar pela conclusão da atualização da interface gráfica antes de continuar a execução. Isso é útil quando a atualização da UI está diretamente relacionada à lógica de negócio da thread.
- Queue: Use quando a atualização da interface gráfica não precisa ser concluída imediatamente. Isso permite que a thread secundária continue sua execução sem esperar, melhorando a performance.
Exemplo Prático: Contador
Vamos criar um exemplo prático onde uma aplicação Delphi atualiza um contador em uma etiqueta na interface gráfica.
- Criar o Projeto
- Crie um novo projeto VCL Forms Application no Delphi.
- Adicionar Componentes
- Adicione um
TButton
e umTLabel
no formulário.
- Adicione um
- Criar a Thread do Contador
- Crie uma nova unit para a thread do contador.
unit untContador;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TCounterThread = class(TThread)
private
FCount: Integer;
FLabel: TLabel;
procedure UpdateLabel;
protected
procedure Execute; override;
public
constructor Create(ALabel: TLabel);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TCounterThread }
constructor TCounterThread.Create(ALabel: TLabel);
begin
inherited Create(False);
FLabel := ALabel;
FreeOnTerminate := True;
end;
procedure TCounterThread.Execute;
begin
FCount := 0;
while not Terminated and (FCount < 100) do
begin
Inc(FCount);
Sleep(100); // Simula uma operação de longa duração
Synchronize(UpdateLabel); // Atualiza a interface gráfica de forma segura Utilizando Syncronize
//Você poderia substituir a linha acima pela linha abaixo caso gostaria que a execução fosse enfileirada
//Queue(UpdateLabel); // Atualiza a interface gráfica de forma segura Utilizando Queue
end;
end;
procedure TCounterThread.UpdateLabel;
begin
FLabel.Caption := 'Contagem: ' + IntToStr(FCount);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
TCounterThread.Create(Label1);
end;
end.
- Iniciar a Thread no Formulário Principal
- Adicione o código para iniciar a thread no evento OnClick do botão.
procedure TForm1.Button1Click(Sender: TObject);
begin
TDownloadThread.Create(ProgressBar1, Label1).Start;
end;
Explicação do Código
- Declaração da Classe
TCounterThread
:TCounterThread
herda deTThread
e é responsável por executar a contagem em segundo plano.- A classe possui um campo
FCount
para armazenar o contador e um campoFLabel
para referenciar oTLabel
que será atualizado. - O construtor
Create
inicializa oFLabel
e defineFreeOnTerminate
comoTrue
para liberar a memória automaticamente quando a thread terminar.
- Método
Execute
:- O método
Execute
é sobrescrito para implementar a lógica da thread. - O loop
while
incrementaFCount
e chamaSleep(100)
para simular uma operação de longa duração. Synchronize(UpdateLabel)
é usado para chamarUpdateLabel
de forma segura no contexto da thread principal.
- O método
- Método
UpdateLabel
:UpdateLabel
atualiza o texto doTLabel
com o valor atual deFCount
.
- Evento
Button1Click
:- Quando o botão é clicado, uma nova instância de
TCounterThread
é criada, passando oTLabel
para a thread.
- Quando o botão é clicado, uma nova instância de
Este exemplo demonstra como sincronizar uma thread com a interface gráfica usando TThread.Synchronize
, garantindo que as atualizações da interface sejam feitas de forma segura e mantendo a aplicação responsiva.
Veja abaixo a ilustração do projeto utilizando Sincronização de Threads com Interface Gráfica:
![]() |
Ilustração do projeto. |
Código fonte do exemplo
Você pode fazer o download do exemplo do projeto através do repositório do github:
https://github.com/Gisele-de-Melo/Sincronizar_Thread_Com_Interface_Grafica
Conclusão
Sincronizar threads com a interface gráfica é essencial para garantir a segurança e a estabilidade das aplicações Delphi. O uso correto de TThread.Synchronize
e TThread.Queue
permite que desenvolvedores atualizem a UI de forma eficiente e segura. Com este conhecimento, você pode criar aplicações Delphi que executam tarefas em segundo plano sem comprometer a responsividade da interface do usuário.
Nenhum comentário:
Postar um comentário