![]() |
| 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
TButtone umTLabelno 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:TCounterThreadherda deTThreade é responsável por executar a contagem em segundo plano.- A classe possui um campo
FCountpara armazenar o contador e um campoFLabelpara referenciar oTLabelque será atualizado. - O construtor
Createinicializa oFLabele defineFreeOnTerminatecomoTruepara 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
whileincrementaFCounte chamaSleep(100)para simular uma operação de longa duração. Synchronize(UpdateLabel)é usado para chamarUpdateLabelde forma segura no contexto da thread principal.
- O método
- Método
UpdateLabel:UpdateLabelatualiza o texto doTLabelcom o valor atual deFCount.
- Evento
Button1Click:- Quando o botão é clicado, uma nova instância de
TCounterThreadé criada, passando oTLabelpara 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.

.png)
Nenhum comentário:
Postar um comentário