|
PROFESSIONAL NEWSGROUPS WINDEV, WEBDEV and WINDEV Mobile |
| | | | | |
| Home → WINDEV 25 → WX (Windev, Webdev e WindevMobile) com Callbacks: Guia Completo com Exemplos Práticos |
| WX (Windev, Webdev e WindevMobile) com Callbacks: Guia Completo com Exemplos Práticos |
| Started by Boller, Sep., 19 2025 8:00 PM - 2 replies |
| |
| | | |
|
| |
Registered member 4,618 messages |
|
| Posted on September, 19 2025 - 8:00 PM |
# WX (Windev, Webdev e WindevMobile) com Callbacks: Guia Completo com Exemplos Práticos
## Introdução
Os callbacks são uma ferramenta fundamental no WinDev para gerenciar operações assíncronas, eventos personalizados e comunicação entre diferentes partes da aplicação. Este guia apresenta métodos simples e eficazes para implementar callbacks em seus projetos WinDev, WebDev e WinDev Mobile.
## O que são Callbacks?
Um callback é uma função que é passada como parâmetro para outra função e é executada em um momento específico, geralmente após a conclusão de uma operação assíncrona ou quando um evento particular ocorre.
### Vantagens dos Callbacks:
- **Flexibilidade**: Permitem personalizar o comportamento sem modificar o código principal - **Reutilização**: O mesmo código pode ter diferentes comportamentos dependendo do callback - **Assincronismo**: Ideais para operações que não bloqueiam a interface - **Modularidade**: Facilitam a separação de responsabilidades
## Implementação Básica de Callbacks
### Exemplo 1: Callback Simples com Procedimento
```wl // Procedimento que aceita um callback PROCEDURE ProcessarDados(sArquivo is string, pCallback is Procedure) bSucesso is boolean // Simula processamento bSucesso = HImportText("MeuArquivo", sArquivo) // Chama o callback com o resultado pCallback(bSucesso, sArquivo) END
// Callback de sucesso PROCEDURE OnProcessamentoCompleto(bSucesso is boolean, sArquivo is string) IF bSucesso THEN Info("Arquivo " + sArquivo + " processado com sucesso!") ELSE Error("Erro ao processar arquivo " + sArquivo) END END
// Uso ProcessarDados("dados.txt", OnProcessamentoCompleto) ```
### Exemplo 2: Callbacks com Parâmetros Múltiplos
```wl // Procedimento para validação com callback PROCEDURE ValidarFormulario(pCallbackSucesso is Procedure, pCallbackErro is Procedure) arrErros is array of strings // Validações IF EDT_Nome = "" THEN Add(arrErros, "Nome é obrigatório") END IF EDT_Email = "" THEN Add(arrErros, "Email é obrigatório") ELSE IF Position(EDT_Email, "@") = 0 THEN Add(arrErros, "Email inválido") END // Executa callback apropriado IF arrErros..Count = 0 THEN pCallbackSucesso() ELSE pCallbackErro(arrErros) END END
// Callbacks PROCEDURE OnValidacaoSucesso() Info("Formulário válido!") // Continua com o processamento END
PROCEDURE OnValidacaoErro(arrErros is array of strings) sMsg is string = "Erros encontrados:" + CR FOR EACH sErro OF arrErros sMsg += "- " + sErro + CR END Error(sMsg) END ```
## Callbacks Avançados
### Exemplo 3: Sistema de Progress com Callback
```wl // Estrutura para informações de progresso STProgress is Structure nPorcentagem is int sEtapa is string nTempoRestante is int END
// Procedimento com callback de progresso PROCEDURE ProcessarLote(arrArquivos is array of strings, pCallbackProgress is Procedure, pCallbackFinal is Procedure) nTotal is int = arrArquivos..Count nProcessados is int = 0 arrResultados is array of strings FOR EACH sArquivo OF arrArquivos // Simula processamento ThreadPause(100) nProcessados++ // Atualiza progresso stProgress is STProgress stProgress.nPorcentagem = (nProcessados * 100) / nTotal stProgress.sEtapa = "Processando: " + ExtractFileName(sArquivo) stProgress.nTempoRestante = (nTotal - nProcessados) * 100 pCallbackProgress(stProgress) // Simula resultado Add(arrResultados, sArquivo + " - OK") END pCallbackFinal(arrResultados) END
// Callbacks PROCEDURE OnProgresso(stProgress is STProgress) PROGBAR_Principal = stProgress.nPorcentagem STC_Status = stProgress.sEtapa STC_Tempo = "Tempo restante: " + stProgress.nTempoRestante + "ms" // Força atualização da interface Multitask() END
PROCEDURE OnProcessamentoFinal(arrResultados is array of strings) Info("Processamento concluído!" + CR + "Arquivos processados: " + arrResultados..Count) END ```
### Exemplo 4: Callback Chain (Encadeamento)
```wl // Sistema de callbacks encadeados PROCEDURE ExecutarChain(arrOperacoes is array of Procedure, pCallbackFinal is Procedure = Null) IF arrOperacoes..Count = 0 THEN IF pCallbackFinal <> Null THEN pCallbackFinal() END RETURN END // Executa primeira operação pPrimeiraOperacao is Procedure = arrOperacoes[1] // Remove da lista Delete(arrOperacoes, 1) // Cria callback para continuar a chain PROCEDURE CallbackContinuar() ExecutarChain(arrOperacoes, pCallbackFinal) END // Executa operação com callback de continuação pPrimeiraOperacao(CallbackContinuar) END
// Operações da chain PROCEDURE Operacao1(pCallback is Procedure) Info("Executando Operação 1") pCallback() END
PROCEDURE Operacao2(pCallback is Procedure) Info("Executando Operação 2") pCallback() END
PROCEDURE Operacao3(pCallback is Procedure) Info("Executando Operação 3") pCallback() END
// Callback final PROCEDURE ChainCompleta() Info("Todas as operações foram concluídas!") END
// Uso arrOps is array of Procedure = [Operacao1, Operacao2, Operacao3] ExecutarChain(arrOps, ChainCompleta) ```
## Callbacks em Operações de Rede
### Exemplo 5: Download com Callback de Progresso
```wl // Classe para download com callbacks CDownload is Class m_sURL is string m_sDestino is string m_pCallbackProgresso is Procedure m_pCallbackCompleto is Procedure m_pCallbackErro is Procedure END
// Método para iniciar download PROCEDURE CDownload::Iniciar(sURL is string, sDestino is string, pProgresso is Procedure = Null, pCompleto is Procedure = Null, pErro is Procedure = Null) m_sURL = sURL m_sDestino = sDestino m_pCallbackProgresso = pProgresso m_pCallbackCompleto = pCompleto m_pCallbackErro = pErro // Inicia download em thread separada ThreadExecute("ThreadDownload", threadNormal, DownloadInterno) END
// Método interno de download PROCEDURE CDownload::DownloadInterno() httpReq is httpRequest httpReq.URL = m_sURL // Configura callback de progresso IF m_pCallbackProgresso <> Null THEN httpReq.ProgressCallback = CallbackProgresso END httpResp is httpResponse = HTTPSend(httpReq) IF httpResp.StatusCode = 200 THEN IF fSaveText(m_sDestino, httpResp.Content) THEN IF m_pCallbackCompleto <> Null THEN ExecuteMainThread(m_pCallbackCompleto, m_sDestino) END ELSE IF m_pCallbackErro <> Null THEN ExecuteMainThread(m_pCallbackErro, "Erro ao salvar arquivo") END END ELSE IF m_pCallbackErro <> Null THEN ExecuteMainThread(m_pCallbackErro, "Erro HTTP: " + httpResp.StatusCode) END END END
// Callback interno de progresso PROCEDURE CDownload::CallbackProgresso(nBytesRecebidos is 8-byte int, nTotalBytes is 8-byte int) IF m_pCallbackProgresso <> Null THEN nPorcentagem is int = (nBytesRecebidos * 100) / nTotalBytes ExecuteMainThread(m_pCallbackProgresso, nPorcentagem, nBytesRecebidos, nTotalBytes) END END
// Uso da classe PROCEDURE OnProgressoDownload(nPorcentagem is int, nRecebido is 8-byte int, nTotal is 8-byte int) PROGBAR_Download = nPorcentagem STC_Status = StringBuild("Baixando: %1% (%2/%3 bytes)", nPorcentagem, nRecebido, nTotal) END
PROCEDURE OnDownloadCompleto(sArquivo is string) Info("Download completo: " + sArquivo) END
PROCEDURE OnDownloadErro(sErro is string) Error("Erro no download: " + sErro) END
// Criação e uso oDownload is CDownload oDownload.Iniciar("http://exemplo.com/arquivo.zip", "C:\temp\arquivo.zip", OnProgressoDownload, OnDownloadCompleto, OnDownloadErro) ```
## Callbacks em WebDev
### Exemplo 6: AJAX com Callbacks
```wl // Procedimento servidor que retorna JSON PROCEDURE WS_BuscarDados(nID is int) stDado is Structure nID is int sNome is string sEmail is string END // Busca dados (simulado) stDado.nID = nID stDado.sNome = "Usuário " + nID stDado.sEmail = "user" + nID + "@email.com" // Retorna JSON RESULT VariantToJSON(stDado) END
// Código navegador com callback PROCEDURE BuscarDadosAsync(nID is int, pCallback is Procedure) // Executa AJAX AJAXExecute(CallbackAJAX, WS_BuscarDados, nID) // Função de callback do AJAX PROCEDURE CallbackAJAX(bSucesso is boolean, sResultado is string, sErro is string) IF bSucesso THEN // Converte JSON para variant vDados is Variant = JSONToVariant(sResultado) pCallback(True, vDados, "") ELSE pCallback(False, Null, sErro) END END END
// Uso no navegador PROCEDURE OnDadosRecebidos(bSucesso is boolean, vDados is Variant, sErro is string) IF bSucesso THEN EDT_Nome = vDados.sNome EDT_Email = vDados.sEmail ELSE Error("Erro ao buscar dados: " + sErro) END END
// Chamada BuscarDadosAsync(123, OnDadosRecebidos) ```
## Callbacks em WinDev Mobile
### Exemplo 7: Localização com Callback
```wl // Procedimento para obter localização PROCEDURE ObterLocalizacao(pCallbackSucesso is Procedure, pCallbackErro is Procedure = Null, nTimeout is int = 30000) // Verifica permissões IF GPSStatus() <> gpsEnabled THEN IF pCallbackErro <> Null THEN pCallbackErro("GPS não disponível") END RETURN END // Inicia obtenção de localização em thread ThreadExecute("ThreadGPS", threadNormal, ObterLocalizacaoThread, pCallbackSucesso, pCallbackErro, nTimeout) END
// Thread para obtenção de localização PROCEDURE ObterLocalizacaoThread(pCallbackSucesso is Procedure, pCallbackErro is Procedure, nTimeout is int) geoPos is geoPosition nTentativas is int = 0 nMaxTentativas is int = nTimeout / 1000 WHILE nTentativas < nMaxTentativas geoPos = GPSGetPosition() IF geoPos.Latitude <> 0 AND geoPos.Longitude <> 0 THEN // Sucesso - executa callback na thread principal ExecuteMainThread(pCallbackSucesso, geoPos) RETURN END nTentativas++ ThreadPause(1000) END // Timeout - executa callback de erro IF pCallbackErro <> Null THEN ExecuteMainThread(pCallbackErro, "Timeout ao obter localização") END END
// Callbacks PROCEDURE OnLocalizacaoObtida(geoPos is geoPosition) Info(StringBuild("Localização obtida:%1Latitude: %2%1Longitude: %3", CR, geoPos.Latitude, geoPos.Longitude)) // Atualiza interface STC_Latitude = geoPos.Latitude STC_Longitude = geoPos.Longitude END
PROCEDURE OnErroLocalizacao(sErro is string) Error("Erro ao obter localização: " + sErro) END
// Uso ObterLocalizacao(OnLocalizacaoObtida, OnErroLocalizacao) ```
## Melhores Práticas
### 1. Sempre Verifique se o Callback é Nulo
```wl IF pCallback <> Null THEN pCallback(parametros...) END ```
### 2. Use ExecuteMainThread para Threads
```wl // Em threads secundárias, sempre execute callbacks na thread principal ExecuteMainThread(pCallback, parametros...) ```
### 3. Tratamento de Erros em Callbacks
```wl PROCEDURE CallbackComTratamento(pCallback is Procedure) TRY pCallback() EXCEPTION Error("Erro no callback: " + ExceptionInfo()) END END ```
### 4. Documentação dos Callbacks
```wl // Sempre documente os parâmetros esperados pelos callbacks // Callback: pCallback(bSucesso is boolean, sResultado is string, sErro is string) PROCEDURE ProcessarComCallback(sEntrada is string, pCallback is Procedure) // ... END ```
### 5. Evite Callbacks Aninhados Excessivos (Callback Hell)
```wl // Em vez de aninhar callbacks, use encadeamento ou promises // Ruim: PROCEDURE CallbackHell() Operacao1(()=> { Operacao2(()=> { Operacao3(()=> { // Código difícil de ler }) }) }) END
// Melhor: Use chain ou sistema de eventos ExecutarChain([Operacao1, Operacao2, Operacao3], CallbackFinal) ```
## Conclusão
Os callbacks são uma ferramenta poderosa no WinDev que permite criar aplicações mais flexíveis, modulares e responsivas. Seja para operações assíncronas, validações dinâmicas, ou comunicação entre componentes, dominar os callbacks irá elevar significativamente a qualidade do seu código.
### Pontos-chave:
- Use callbacks para operações assíncronas e eventos personalizados - Sempre verifique se o callback não é nulo antes de executá-lo - Em threads secundárias, use ExecuteMainThread para executar callbacks - Documente claramente os parâmetros esperados pelos callbacks - Evite o “callback hell” usando encadeamento ou sistemas de eventos
Implementar esses padrões em seus projetos WinDev, WebDev e WinDev Mobile resultará em código mais limpo, manutenível e profissional.
-- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianoboller http://wxinformatica.com.br/ |
| |
| |
| | | |
|
| | |
| |
Registered member 4,618 messages |
|
| Posted on September, 19 2025 - 8:02 PM |
Conceitos Fundamentais: • O que são callbacks e suas vantagens • Implementação básica com procedimentos 📱 Exemplos Práticos por Plataforma: • WinDev: Validação de formulários, sistema de progresso, encadeamento de operações • WebDev: Requisições AJAX com callbacks • WinDev Mobile: Obtenção de localização GPS 🚀 Técnicas Avançadas: • Callback chains (encadeamento) • Download com progresso em tempo real • Sistema de eventos personalizados • Tratamento de threads com ExecuteMainThread ✅ Melhores Práticas: • Verificação de callbacks nulos • Tratamento de erros • Documentação adequada • Como evitar “callback hell” O artigo fornece código WLanguage funcional que você pode usar diretamente em seus projetos. Cada exemplo é documentado e inclui casos de uso reais que você provavelmente encontrará no desenvolvimento com a plataforma PC Soft.
-- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianoboller http://wxinformatica.com.br/ |
| |
| |
| | | |
|
| | |
| |
Registered member 4,618 messages |
|
| Posted on September, 19 2025 - 8:06 PM |
Expandir o artigo com 9 novos exemplos avançados baseados em técnicas reais do WinDev: 🆕 Novos Exemplos Adicionados: Técnicas Avançadas: • Exemplo 8: Closures com Timer (WinDev 20+) • Exemplo 9: Factory de Callbacks Personalizados • Exemplo 10: Callbacks com APIs/DLLs Windows • Exemplo 11: Sistema de Notificações Multi-Callback Padrões Arquiteturais: • Exemplo 12: Sistema de Callback com Filtros • Exemplo 13: Observer Pattern Completo • Exemplo 14: Debug e Profiling de Callbacks Técnicas de Performance: • Exemplo 15: Promise-like Implementation • Exemplo 16: Throttle e Debounce (Rate Limiting) 🎯 Destaques dos Novos Exemplos: 🔥 Closures e Contexto: • Timer com closure que “lembra” variáveis locais • Factory que cria callbacks personalizados com estado ⚡ Performance e Control: • Throttle para limitar execuções por tempo • Debounce para campos de pesquisa • Sistema de filtros condicionais 🏗️ Arquitetura Profissional: • Observer Pattern completo • Sistema de notificações extensível • Promise-like para async/await style 🐛 Debugging: • Wrapper de debug com timing • Logging automático de parâmetros • Tratamento de exceções em callbacks 🔌 Integração: • Callbacks com DLLs Windows (EnumWindows) • APIs externas com callback nativo Esses exemplos cobrem desde técnicas básicas até padrões arquiteturais avançados, fornecendo um arsenal completo para desenvolver aplicações WinDev de nível profissional com callbacks eficientes e maintíveis!
# WinDev e Callbacks: Guia Completo com Exemplos Práticos
## Introdução
Os callbacks são uma ferramenta fundamental no WinDev para gerenciar operações assíncronas, eventos personalizados e comunicação entre diferentes partes da aplicação. Este guia apresenta métodos simples e eficazes para implementar callbacks em seus projetos WinDev, WebDev e WinDev Mobile.
## O que são Callbacks?
Um callback é uma função que é passada como parâmetro para outra função e é executada em um momento específico, geralmente após a conclusão de uma operação assíncrona ou quando um evento particular ocorre.
### Vantagens dos Callbacks:
- **Flexibilidade**: Permitem personalizar o comportamento sem modificar o código principal - **Reutilização**: O mesmo código pode ter diferentes comportamentos dependendo do callback - **Assincronismo**: Ideais para operações que não bloqueiam a interface - **Modularidade**: Facilitam a separação de responsabilidades
## Implementação Básica de Callbacks
### Exemplo 1: Callback Simples com Procedimento
```wl // Procedimento que aceita um callback PROCEDURE ProcessarDados(sArquivo is string, pCallback is Procedure) bSucesso is boolean // Simula processamento bSucesso = HImportText("MeuArquivo", sArquivo) // Chama o callback com o resultado pCallback(bSucesso, sArquivo) END
// Callback de sucesso PROCEDURE OnProcessamentoCompleto(bSucesso is boolean, sArquivo is string) IF bSucesso THEN Info("Arquivo " + sArquivo + " processado com sucesso!") ELSE Error("Erro ao processar arquivo " + sArquivo) END END
// Uso ProcessarDados("dados.txt", OnProcessamentoCompleto) ```
### Exemplo 2: Callbacks com Parâmetros Múltiplos
```wl // Procedimento para validação com callback PROCEDURE ValidarFormulario(pCallbackSucesso is Procedure, pCallbackErro is Procedure) arrErros is array of strings // Validações IF EDT_Nome = "" THEN Add(arrErros, "Nome é obrigatório") END IF EDT_Email = "" THEN Add(arrErros, "Email é obrigatório") ELSE IF Position(EDT_Email, "@") = 0 THEN Add(arrErros, "Email inválido") END // Executa callback apropriado IF arrErros..Count = 0 THEN pCallbackSucesso() ELSE pCallbackErro(arrErros) END END
// Callbacks PROCEDURE OnValidacaoSucesso() Info("Formulário válido!") // Continua com o processamento END
PROCEDURE OnValidacaoErro(arrErros is array of strings) sMsg is string = "Erros encontrados:" + CR FOR EACH sErro OF arrErros sMsg += "- " + sErro + CR END Error(sMsg) END ```
## Callbacks Avançados
### Exemplo 3: Sistema de Progress com Callback
```wl // Estrutura para informações de progresso STProgress is Structure nPorcentagem is int sEtapa is string nTempoRestante is int END
// Procedimento com callback de progresso PROCEDURE ProcessarLote(arrArquivos is array of strings, pCallbackProgress is Procedure, pCallbackFinal is Procedure) nTotal is int = arrArquivos..Count nProcessados is int = 0 arrResultados is array of strings FOR EACH sArquivo OF arrArquivos // Simula processamento ThreadPause(100) nProcessados++ // Atualiza progresso stProgress is STProgress stProgress.nPorcentagem = (nProcessados * 100) / nTotal stProgress.sEtapa = "Processando: " + ExtractFileName(sArquivo) stProgress.nTempoRestante = (nTotal - nProcessados) * 100 pCallbackProgress(stProgress) // Simula resultado Add(arrResultados, sArquivo + " - OK") END pCallbackFinal(arrResultados) END
// Callbacks PROCEDURE OnProgresso(stProgress is STProgress) PROGBAR_Principal = stProgress.nPorcentagem STC_Status = stProgress.sEtapa STC_Tempo = "Tempo restante: " + stProgress.nTempoRestante + "ms" // Força atualização da interface Multitask() END
PROCEDURE OnProcessamentoFinal(arrResultados is array of strings) Info("Processamento concluído!" + CR + "Arquivos processados: " + arrResultados..Count) END ```
### Exemplo 4: Callback Chain (Encadeamento)
```wl // Sistema de callbacks encadeados PROCEDURE ExecutarChain(arrOperacoes is array of Procedure, pCallbackFinal is Procedure = Null) IF arrOperacoes..Count = 0 THEN IF pCallbackFinal <> Null THEN pCallbackFinal() END RETURN END // Executa primeira operação pPrimeiraOperacao is Procedure = arrOperacoes[1] // Remove da lista Delete(arrOperacoes, 1) // Cria callback para continuar a chain PROCEDURE CallbackContinuar() ExecutarChain(arrOperacoes, pCallbackFinal) END // Executa operação com callback de continuação pPrimeiraOperacao(CallbackContinuar) END
// Operações da chain PROCEDURE Operacao1(pCallback is Procedure) Info("Executando Operação 1") pCallback() END
PROCEDURE Operacao2(pCallback is Procedure) Info("Executando Operação 2") pCallback() END
PROCEDURE Operacao3(pCallback is Procedure) Info("Executando Operação 3") pCallback() END
// Callback final PROCEDURE ChainCompleta() Info("Todas as operações foram concluídas!") END
// Uso arrOps is array of Procedure = [Operacao1, Operacao2, Operacao3] ExecutarChain(arrOps, ChainCompleta) ```
## Callbacks em Operações de Rede
### Exemplo 5: Download com Callback de Progresso
```wl // Classe para download com callbacks CDownload is Class m_sURL is string m_sDestino is string m_pCallbackProgresso is Procedure m_pCallbackCompleto is Procedure m_pCallbackErro is Procedure END
// Método para iniciar download PROCEDURE CDownload::Iniciar(sURL is string, sDestino is string, pProgresso is Procedure = Null, pCompleto is Procedure = Null, pErro is Procedure = Null) m_sURL = sURL m_sDestino = sDestino m_pCallbackProgresso = pProgresso m_pCallbackCompleto = pCompleto m_pCallbackErro = pErro // Inicia download em thread separada ThreadExecute("ThreadDownload", threadNormal, DownloadInterno) END
// Método interno de download PROCEDURE CDownload::DownloadInterno() httpReq is httpRequest httpReq.URL = m_sURL // Configura callback de progresso IF m_pCallbackProgresso <> Null THEN httpReq.ProgressCallback = CallbackProgresso END httpResp is httpResponse = HTTPSend(httpReq) IF httpResp.StatusCode = 200 THEN IF fSaveText(m_sDestino, httpResp.Content) THEN IF m_pCallbackCompleto <> Null THEN ExecuteMainThread(m_pCallbackCompleto, m_sDestino) END ELSE IF m_pCallbackErro <> Null THEN ExecuteMainThread(m_pCallbackErro, "Erro ao salvar arquivo") END END ELSE IF m_pCallbackErro <> Null THEN ExecuteMainThread(m_pCallbackErro, "Erro HTTP: " + httpResp.StatusCode) END END END
// Callback interno de progresso PROCEDURE CDownload::CallbackProgresso(nBytesRecebidos is 8-byte int, nTotalBytes is 8-byte int) IF m_pCallbackProgresso <> Null THEN nPorcentagem is int = (nBytesRecebidos * 100) / nTotalBytes ExecuteMainThread(m_pCallbackProgresso, nPorcentagem, nBytesRecebidos, nTotalBytes) END END
// Uso da classe PROCEDURE OnProgressoDownload(nPorcentagem is int, nRecebido is 8-byte int, nTotal is 8-byte int) PROGBAR_Download = nPorcentagem STC_Status = StringBuild("Baixando: %1% (%2/%3 bytes)", nPorcentagem, nRecebido, nTotal) END
PROCEDURE OnDownloadCompleto(sArquivo is string) Info("Download completo: " + sArquivo) END
PROCEDURE OnDownloadErro(sErro is string) Error("Erro no download: " + sErro) END
// Criação e uso oDownload is CDownload oDownload.Iniciar("http://exemplo.com/arquivo.zip", "C:\temp\arquivo.zip", OnProgressoDownload, OnDownloadCompleto, OnDownloadErro) ```
## Callbacks em WebDev
### Exemplo 6: AJAX com Callbacks
```wl // Procedimento servidor que retorna JSON PROCEDURE WS_BuscarDados(nID is int) stDado is Structure nID is int sNome is string sEmail is string END // Busca dados (simulado) stDado.nID = nID stDado.sNome = "Usuário " + nID stDado.sEmail = "user" + nID + "@email.com" // Retorna JSON RESULT VariantToJSON(stDado) END
// Código navegador com callback PROCEDURE BuscarDadosAsync(nID is int, pCallback is Procedure) // Executa AJAX AJAXExecute(CallbackAJAX, WS_BuscarDados, nID) // Função de callback do AJAX PROCEDURE CallbackAJAX(bSucesso is boolean, sResultado is string, sErro is string) IF bSucesso THEN // Converte JSON para variant vDados is Variant = JSONToVariant(sResultado) pCallback(True, vDados, "") ELSE pCallback(False, Null, sErro) END END END
// Uso no navegador PROCEDURE OnDadosRecebidos(bSucesso is boolean, vDados is Variant, sErro is string) IF bSucesso THEN EDT_Nome = vDados.sNome EDT_Email = vDados.sEmail ELSE Error("Erro ao buscar dados: " + sErro) END END
// Chamada BuscarDadosAsync(123, OnDadosRecebidos) ```
## Callbacks em WinDev Mobile
### Exemplo 7: Localização com Callback
```wl // Procedimento para obter localização PROCEDURE ObterLocalizacao(pCallbackSucesso is Procedure, pCallbackErro is Procedure = Null, nTimeout is int = 30000) // Verifica permissões IF GPSStatus() <> gpsEnabled THEN IF pCallbackErro <> Null THEN pCallbackErro("GPS não disponível") END RETURN END // Inicia obtenção de localização em thread ThreadExecute("ThreadGPS", threadNormal, ObterLocalizacaoThread, pCallbackSucesso, pCallbackErro, nTimeout) END
// Thread para obtenção de localização PROCEDURE ObterLocalizacaoThread(pCallbackSucesso is Procedure, pCallbackErro is Procedure, nTimeout is int) geoPos is geoPosition nTentativas is int = 0 nMaxTentativas is int = nTimeout / 1000 WHILE nTentativas < nMaxTentativas geoPos = GPSGetPosition() IF geoPos.Latitude <> 0 AND geoPos.Longitude <> 0 THEN // Sucesso - executa callback na thread principal ExecuteMainThread(pCallbackSucesso, geoPos) RETURN END nTentativas++ ThreadPause(1000) END // Timeout - executa callback de erro IF pCallbackErro <> Null THEN ExecuteMainThread(pCallbackErro, "Timeout ao obter localização") END END
// Callbacks PROCEDURE OnLocalizacaoObtida(geoPos is geoPosition) Info(StringBuild("Localização obtida:%1Latitude: %2%1Longitude: %3", CR, geoPos.Latitude, geoPos.Longitude)) // Atualiza interface STC_Latitude = geoPos.Latitude STC_Longitude = geoPos.Longitude END
PROCEDURE OnErroLocalizacao(sErro is string) Error("Erro ao obter localização: " + sErro) END
// Uso ObterLocalizacao(OnLocalizacaoObtida, OnErroLocalizacao) ```
## Melhores Práticas
### 1. Sempre Verifique se o Callback é Nulo
```wl IF pCallback <> Null THEN pCallback(parametros...) END ```
### 2. Use ExecuteMainThread para Threads
```wl // Em threads secundárias, sempre execute callbacks na thread principal ExecuteMainThread(pCallback, parametros...) ```
### 3. Tratamento de Erros em Callbacks
```wl PROCEDURE CallbackComTratamento(pCallback is Procedure) TRY pCallback() EXCEPTION Error("Erro no callback: " + ExceptionInfo()) END END ```
### 4. Documentação dos Callbacks
```wl // Sempre documente os parâmetros esperados pelos callbacks // Callback: pCallback(bSucesso is boolean, sResultado is string, sErro is string) PROCEDURE ProcessarComCallback(sEntrada is string, pCallback is Procedure) // ... END ```
### 5. Evite Callbacks Aninhados Excessivos (Callback Hell)
```wl // Em vez de aninhar callbacks, use encadeamento ou promises // Ruim: PROCEDURE CallbackHell() Operacao1(()=> { Operacao2(()=> { Operacao3(()=> { // Código difícil de ler }) }) }) END
// Melhor: Use chain ou sistema de eventos ExecutarChain([Operacao1, Operacao2, Operacao3], CallbackFinal) ```
## Closures e Procedimentos Internos (WinDev 20+)
### Exemplo 8: Timer com Closure
```wl // Procedimento que usa closure com timer PROCEDURE ExemploClosure() nContador is int = 0 // Closure - procedimento interno que acessa variável local PROCEDURE INTERNAL TimerCallback() nContador++ Info("Contador: " + nContador) // Para após 5 execuções IF nContador >= 5 THEN TimerEnd("MonTimer") END END // Inicia timer com a closure Timer("MonTimer", 1000, TimerCallback) END ```
### Exemplo 9: Factory de Callbacks Personalizados
```wl // Factory que cria callbacks específicos com estado PROCEDURE CriarCallbackPersonalizado(sNome is string, nIDUsuario is int) : Procedure // Retorna uma closure que "lembra" dos parâmetros PROCEDURE INTERNAL CallbackPersonalizado(bSucesso is boolean, vDados is Variant) sLogEntry is string = StringBuild("[%1] Usuário %2: %3", DateTimeToString(Now()), nIDUsuario, sNome) IF bSucesso THEN sLogEntry += " - Sucesso: " + VariantToJSON(vDados) ELSE sLogEntry += " - Erro: " + vDados END // Log personalizado Trace(sLogEntry) // Notificação específica do usuário Info(StringBuild("Operação para %1 (ID: %2) %3!", sNome, nIDUsuario, iif(bSucesso, "concluída", "falhou"))) END RESULT CallbackPersonalizado END
// Uso da factory pCallbackJoao is Procedure = CriarCallbackPersonalizado("João Silva", 123) pCallbackMaria is Procedure = CriarCallbackPersonalizado("Maria Santos", 456)
// Cada callback tem seu próprio contexto ProcessarDados("dados1.txt", pCallbackJoao) ProcessarDados("dados2.txt", pCallbackMaria) ```
## Callbacks com APIs Externas
### Exemplo 10: Callback com DLL Windows
```wl // Declaração de callback para API Windows PROCEDURE CallbackEnumWindows(hWnd is system int, lParam is system int) : boolean sTitle is string = GetWindowText(hWnd, 256) sClassName is string = GetClassName(hWnd, 256) IF Length(sTitle) > 0 THEN // Adiciona à lista (passada via lParam) pLista is Pointer = lParam ListAdd(pLista^, sTitle + " (" + sClassName + ")") END RESULT True // Continua enumeração END
// Procedimento principal PROCEDURE ListarJanelas() : array of strings arrJanelas is array of strings // Chama API Windows com callback EnumWindows(&CallbackEnumWindows, &arrJanelas) RESULT arrJanelas END ```
### Exemplo 11: Sistema de Notificações com Múltiplos Callbacks
```wl // Classe para gerenciar notificações CNotificationManager is Class m_arrCallbacks is associative array of array of Procedure END
// Registrar callback para evento PROCEDURE CNotificationManager::Subscribe(sEvento is string, pCallback is Procedure) IF NOT m_arrCallbacks..Exist[sEvento] THEN m_arrCallbacks[sEvento] = new array of Procedure END Add(m_arrCallbacks[sEvento], pCallback) END
// Disparar evento PROCEDURE CNotificationManager::Trigger(sEvento is string, vParametros is Variant = Null) IF m_arrCallbacks..Exist[sEvento] THEN FOR EACH pCallback OF m_arrCallbacks[sEvento] TRY IF vParametros = Null THEN pCallback() ELSE pCallback(vParametros) END EXCEPTION Error("Erro no callback: " + ExceptionInfo()) END END END END
// Remover callback PROCEDURE CNotificationManager::Unsubscribe(sEvento is string, pCallback is Procedure) IF m_arrCallbacks..Exist[sEvento] THEN nIndex is int = Seek(m_arrCallbacks[sEvento], pCallback) IF nIndex > 0 THEN Delete(m_arrCallbacks[sEvento], nIndex) END END END
// Uso do sistema de notificações GLOBAL g_oNotificationManager is CNotificationManager
// Callbacks específicos PROCEDURE OnUsuarioLogou(vDados is Variant) Info("Usuário " + vDados.sNome + " fez login") END
PROCEDURE OnProdutoVendido(vDados is Variant) Info("Produto vendido: " + vDados.sProduto + " - R$ " + vDados.nValor) END
PROCEDURE OnErroSistema(vDados is Variant) Error("Erro do sistema: " + vDados.sErro) // Enviar email, log, etc. END
// Registrar eventos g_oNotificationManager.Subscribe("usuario_login", OnUsuarioLogou) g_oNotificationManager.Subscribe("produto_vendido", OnProdutoVendido) g_oNotificationManager.Subscribe("erro_sistema", OnErroSistema)
// Disparar eventos stDadosLogin is Structure sNome is string = "João" nID is int = 123 END g_oNotificationManager.Trigger("usuario_login", stDadosLogin) ```
## Callbacks Condicionais e Filtros
### Exemplo 12: Sistema de Callback com Filtros
```wl // Estrutura para callback com filtro STCallbackFiltrado is Structure pCallback is Procedure pFiltro is Procedure // Função que retorna boolean sPrioridade is string END
// Gerenciador de callbacks filtrados PROCEDURE ExecutarCallbacksFiltrados(arrCallbacks is array of STCallbackFiltrado, vDados is Variant) // Ordena por prioridade (alta, media, baixa) ArraySort(arrCallbacks, asAscending, "sPrioridade") FOR EACH stCallback OF arrCallbacks bExecutar is boolean = True // Aplica filtro se existir IF stCallback.pFiltro <> Null THEN TRY bExecutar = stCallback.pFiltro(vDados) EXCEPTION bExecutar = False Trace("Erro no filtro: " + ExceptionInfo()) END END // Executa callback se passou no filtro IF bExecutar THEN TRY stCallback.pCallback(vDados) EXCEPTION Trace("Erro no callback: " + ExceptionInfo()) END END END END
// Filtros PROCEDURE FiltroUsuarioAdmin(vUsuario is Variant) : boolean RESULT vUsuario.sTipo = "ADMIN" END
PROCEDURE FiltroValorAlto(vTransacao is Variant) : boolean RESULT vTransacao.nValor >= 1000 END
// Callbacks PROCEDURE CallbackAdminLogin(vUsuario is Variant) Info("ADMIN logou: " + vUsuario.sNome) // Registra log especial para admins END
PROCEDURE CallbackTransacaoAlta(vTransacao is Variant) Info("Transação de alto valor: R$ " + vTransacao.nValor) // Notifica gerência END
// Configuração arrCallbacksLogin is array of STCallbackFiltrado stCallbackAdmin is STCallbackFiltrado stCallbackAdmin.pCallback = CallbackAdminLogin stCallbackAdmin.pFiltro = FiltroUsuarioAdmin stCallbackAdmin.sPrioridade = "alta" Add(arrCallbacksLogin, stCallbackAdmin) ```
## Padrão Observer com Callbacks
### Exemplo 13: Observer Pattern Implementado
```wl // Interface Observer CObserver is Class PROCEDURE OnNotificacao(sEvento is string, vDados is Variant) : virtual END
// Observador concreto CLogObserver inherits CObserver PROCEDURE OnNotificacao(sEvento is string, vDados is Variant) : override sLog is string = StringBuild("[%1] %2: %3", DateTimeToString(Now()), sEvento, VariantToJSON(vDados)) fWriteLine("log.txt", sLog) END END
// Subject observável CSubjectObservavel is Class m_arrObservers is array of CObserver END
PROCEDURE CSubjectObservavel::AdicionarObserver(oObserver is CObserver) Add(m_arrObservers, oObserver) END
PROCEDURE CSubjectObservavel::RemoverObserver(oObserver is CObserver) nIndex is int = Seek(m_arrObservers, oObserver) IF nIndex > 0 THEN Delete(m_arrObservers, nIndex) END END
PROCEDURE CSubjectObservavel::NotificarObservers(sEvento is string, vDados is Variant) FOR EACH oObserver OF m_arrObservers oObserver.OnNotificacao(sEvento, vDados) END END
// Uso com callbacks funcionais também PROCEDURE CSubjectObservavel::AdicionarCallbackObserver(pCallback is Procedure) // Cria adapter que converte callback em observer PROCEDURE INTERNAL CallbackAdapter(sEvento is string, vDados is Variant) pCallback(sEvento, vDados) END // Pode adicionar como observer funcional // (implementação específica dependeria da arquitetura) END ```
## Debugging e Profiling de Callbacks
### Exemplo 14: Sistema de Debug para Callbacks
```wl // Wrapper para debug de callbacks PROCEDURE WrapCallbackComDebug(pCallback is Procedure, sNome is string) : Procedure PROCEDURE INTERNAL CallbackComDebug(*) dInicio is DateTime = Now() sParametros is string = "" // Constrói string dos parâmetros (limitado) FOR nI = 1 _TO_ MyParameters()..Count IF nI > 1 THEN sParametros += ", " sParametros += VariantToString(MyParameters()[nI]) END Trace(StringBuild("CALLBACK [%1] INICIADO - Parâmetros: %2", sNome, sParametros)) TRY // Executa callback original ExecuteProcedure(pCallback, MyParameters()) dFim is DateTime = Now() nDuracao is int = DateTimeDifference(dFim, dInicio) Trace(StringBuild("CALLBACK [%1] CONCLUÍDO - Duração: %2ms", sNome, nDuracao)) EXCEPTION Trace(StringBuild("CALLBACK [%1] ERRO: %2", sNome, ExceptionInfo())) Error("Erro no callback " + sNome + ": " + ExceptionInfo()) END END RESULT CallbackComDebug END
// Uso do wrapper de debug PROCEDURE MeuCallback(sResultado is string) // Simula processamento ThreadPause(100) Info("Resultado: " + sResultado) END
// Wrapping do callback para debug pCallbackComDebug is Procedure = WrapCallbackComDebug(MeuCallback, "ProcessamentoArquivo")
// Usar o callback com debug ProcessarDados("teste.txt", pCallbackComDebug) ```
## Callbacks Assíncronos Avançados
### Exemplo 15: Promise-like com Callbacks
```wl // Classe que simula Promises CPromise is Class m_bCompleto is boolean = False m_bSucesso is boolean = False m_vResultado is Variant m_sErro is string m_arrCallbacksSucesso is array of Procedure m_arrCallbacksErro is array of Procedure END
// Método Then (para sucesso) PROCEDURE CPromise::Then(pCallback is Procedure) : CPromise IF m_bCompleto THEN IF m_bSucesso THEN pCallback(m_vResultado) END ELSE Add(m_arrCallbacksSucesso, pCallback) END RESULT this END
// Método Catch (para erro) PROCEDURE CPromise::Catch(pCallback is Procedure) : CPromise IF m_bCompleto THEN IF NOT m_bSucesso THEN pCallback(m_sErro) END ELSE Add(m_arrCallbacksErro, pCallback) END RESULT this END
// Resolver promise com sucesso PROCEDURE CPromise::Resolver(vResultado is Variant) IF m_bCompleto THEN RETURN m_bCompleto = True m_bSucesso = True m_vResultado = vResultado // Executa todos os callbacks de sucesso FOR EACH pCallback OF m_arrCallbacksSucesso pCallback(vResultado) END END
// Rejeitar promise com erro PROCEDURE CPromise::Rejeitar(sErro is string) IF m_bCompleto THEN RETURN m_bCompleto = True m_bSucesso = False m_sErro = sErro // Executa todos os callbacks de erro FOR EACH pCallback OF m_arrCallbacksErro pCallback(sErro) END END
// Uso da Promise PROCEDURE ProcessarComPromise(sArquivo is string) : CPromise oPromise is CPromise // Processa em thread ThreadExecute("ProcessThread", threadNormal, ThreadProcessamento, oPromise, sArquivo) RESULT oPromise END
PROCEDURE ThreadProcessamento(oPromise is CPromise, sArquivo is string) IF fFileExist(sArquivo) THEN sConteudo is string = fLoadText(sArquivo) ExecuteMainThread(oPromise.Resolver, sConteudo) ELSE ExecuteMainThread(oPromise.Rejeitar, "Arquivo não encontrado: " + sArquivo) END END
// Uso elegante com encadeamento ProcessarComPromise("dados.txt") .Then((sConteudo) => { Info("Sucesso: " + Left(sConteudo, 50) + "...") }) .Catch((sErro) => { Error("Erro: " + sErro) }) ```
## Callbacks com Rate Limiting
### Exemplo 16: Throttle e Debounce
```wl // Implementação de Throttle (limita execuções por tempo) PROCEDURE ThrottleCallback(pCallback is Procedure, nIntervaloMS is int) : Procedure LOCAL dUltimaExecucao is DateTime PROCEDURE INTERNAL CallbackThrottled(*) dAgora is DateTime = Now() IF DateTimeDifference(dAgora, dUltimaExecucao) >= nIntervaloMS THEN dUltimaExecucao = dAgora ExecuteProcedure(pCallback, MyParameters()) END END RESULT CallbackThrottled END
// Implementação de Debounce (executa apenas após período sem chamadas) PROCEDURE DebounceCallback(pCallback is Procedure, nDelayMS is int) : Procedure LOCAL sTimerID is string = GetIdentifier() PROCEDURE INTERNAL CallbackDebounced(*) // Cancela timer anterior se existir TimerEnd(sTimerID) // Captura parâmetros atuais arrParametros is array of Variant FOR nI = 1 _TO_ MyParameters()..Count Add(arrParametros, MyParameters()[nI]) END // Cria closure que será executada pelo timer PROCEDURE INTERNAL ExecutarCallback() ExecuteProcedure(pCallback, arrParametros) END // Agenda execução Timer(sTimerID, nDelayMS, ExecutarCallback) END RESULT CallbackDebounced END
// Exemplo de uso PROCEDURE OnPesquisar(sTexto is string) // Simula pesquisa cara Info("Pesquisando: " + sTexto) END
// Callback com debounce para campo de pesquisa pCallbackDebounced is Procedure = DebounceCallback(OnPesquisar, 500)
// No evento de modificação do campo PROCEDURE EDT_Pesquisa::OnModification() pCallbackDebounced(EDT_Pesquisa) END ```
## Conclusão
Os callbacks são uma ferramenta poderosa no WinDev que permite criar aplicações mais flexíveis, modulares e responsivas. Com as técnicas avançadas apresentadas, incluindo closures, promises, observers e rate limiting, você pode criar arquiteturas sofisticadas que rivalizam com frameworks modernos.
### Pontos-chave adicionais:
- **Closures (WinDev 20+)**: Permitem callbacks que “lembram” do contexto - **Procedimentos Internos**: Ideais para callbacks específicos e temporários - **Rate Limiting**: Throttle e Debounce para controlar frequência de execução - **Promise-like**: Padrão para gerenciar operações assíncronas de forma elegante - **Observer Pattern**: Para sistemas de notificação escaláveis - **Debug Wrappers**: Facilita debugging e profiling de callbacks - **APIs Externas**: Integração com DLLs Windows usando callbacks
### Boas Práticas Específicas:
- Use closures para callbacks que precisam de contexto - Implemente rate limiting em callbacks de interface (pesquisa, validação) - Wrapping para debug em desenvolvimento - Sistema de filtros para callbacks condicionais - Pattern Observer para arquiteturas orientadas a eventos
Implementar esses padrões avançados em seus projetos WinDev, WebDev e WinDev Mobile resultará em código mais limpo, manutenível, profissional e com melhor performance.
-- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianoboller http://wxinformatica.com.br/Message modified, September, 19 2025 - 8:08 PM |
| |
| |
| | | |
|
| | | | |
| | |
| | |
| |
|
|
|