
Í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:

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.
Posts Relacionados
Delphi para Android e iOS
Delphi Start
Programando em Delphi XE
Aprenda programar Delphi
Banco de Dados RAD Delphi
Delphi Programming Projects