TheCodeNaked

Validator4D: Validação Fluente e Eficiente para Delphi FMX (Copy)


Resumo: O Validator4D centraliza e padroniza a validação de formulários FMX com API fluente, i18n, máscaras, feedback visual e validação em tempo real opcional. Este guia traz Quick Start, exemplos práticos, receitas de uso, arquitetura e boas práticas.

Quick Start

Em 30 segundos, do zero ao “Salvar com validação”.
uses Validator4D;

var
  V: IFormValidator;

procedure TForm1.FormCreate(Sender: TObject);
begin
  V := CreateFormValidator
        .WithAutoTrim(True)
        .WithOnValidated(
          procedure(C: TControl; Ok: Boolean; const Msg: string)
          begin
            // Ex.: trate visualmente aqui (cor do controle/label, etc.)
          end);

  V.ForControl(EditEmail)
     .Required(_('Obrigatório'))
     .Email(_('E-mail inválido'))
     .WithErrorLabel(LabelEmailErr);

  V.AttachOnExit(Self); // ou V.AttachLive(Self) para validar enquanto digita
end;

procedure TForm1.BtnSalvarClick(Sender: TObject);
begin
  if V.ValidateAll then
    ShowMessage('OK!')
  else
    ShowMessage('Há campos pendentes.');
end;

Quando usar cada modo

ModoQuando usarPrósContras
AttachOnExitFormulários longos / digitação intensaMenos interrupção ao usuárioFeedback menos imediato
AttachLiveCampos críticos / máscara / autocompletarFeedback imediato (com debounce)Requer debounce (já incluso)

Motivação (resumo)

Em apps comerciais FMX, validação consistente evita retrabalho e melhora a UX. O Validator4D centraliza regras, padroniza mensagens (i18n) e oferece API fluente com validação em tempo real, reduzindo código repetido e divergências entre telas/equipes. Também facilita manutenção, reutilização e internacionalização (PT/EN/JA).


Exemplos de Uso

1) Básico (obrigatório + e-mail)

V.ForControl(EditEmail)
 .Required(_('Obrigatório'))
 .Email(_('E-mail inválido'))
 .WithErrorLabel(LabelEmailErr);

2) Datas (MinDate/MaxDate/BetweenDates)

uses System.SysUtils, System.DateUtils;

V.ForControl(EditDate)
  .DateFormat('yyyy-mm-dd', _('Use AAAA-MM-DD'))
  .MinDate(EncodeDate(2025, 1, 1),  _('Data mínima: %s'), ['2025-01-01'])
  .MaxDate(EncodeDate(2025,12,31),  _('Data máxima: %s'), ['2025-12-31'])
  .BetweenDates(
      EncodeDate(2025, 1, 1),
      EncodeDate(2025,12,31),
      _('Data fora do intervalo: %s ~ %s'), ['2025-01-01','2025-12-31'])
  .WithErrorLabel(LabelDateErr);

3) Horas (MinTime/MaxTime)

EncodeTime(HH, MM, SS, MS) — horas, minutos, segundos, milissegundos. Ex.: EncodeTime(9,0,0,0) = 09:00:00.000.
V.ForControl(EditTime)
  .TimeFormat('hh:nn', _('Use HH:MM'))
  .MinTime(EncodeTime(9, 0, 0, 0),  _('Horário inicial: %s'), ['09:00'])
  .MaxTime(EncodeTime(18, 0, 0, 0), _('Horário final: %s'),   ['18:00'])
  .WithErrorLabel(LabelTimeErr);

4) ListBox e CheckBox

V.ForControl(ListBoxServices)
  .MinSelected(1,  _('Selecione ao menos 1'))
  .MaxSelected(3,  _('No máximo 3 itens'));

V.ForControl(ChkTerms)
  .Checked(_('É necessário aceitar os termos'));

5) Máscaras rápidas

V.ForControl(EditPhoneJP).Mask('00-0000-0000', _('Telefone inválido'));
V.ForControl(EditCPF).Mask('000.000.000-00', _('CPF inválido'));

6) Regras customizadas

V.ForControl(EditSKU)
 .Custom(
   procedure(const S: string; var Ok: Boolean; var Msg: string)
   begin
     Ok := (S <> '') and S.StartsWith('SKU-') and (S.Length = 12);
     if not Ok then Msg := _('SKU no formato SKU-XXXXXXXX');
   end);

Arquitetura e Fluxo

  • InterfacesIFormValidator (config/execução) e IValidationRule (regras encadeáveis).
  • ImplementaçõesTFormValidator e TControlRules (mapa controle→regras, cache RTTI, curto-circuito na 1ª falha).
  • Fluxo de validação:
    1. Obtenção do texto/valor do controle.
    2. Auto-trim opcional.
    3. Campo opcional? (WhenFilled) → se vazio, pula demais.
    4. Execução sequencial das regras → para na primeira falha.
    5. Feedback visual (controle/rótulo) + callbacks (OnValidated global e por controle).

Receitas Rápidas (copy & paste)

Obrigatório condicional

V.ForControl(EditExt)
  .When( function: Boolean begin Result := EditBase.Text <> ''; end )
  .Required(_('Campo obrigatório quando o outro foi preenchido'));

ComboBox com placeholder (primeiro item)

V.ForControl(CmbCity)
  .RequireNonFirst(_('Selecione uma cidade válida'));

URL / E-mail / IP

V.ForControl(EditUrl).URL(_('URL inválida'));
V.ForControl(EditEmail).Email(_('E-mail inválido'));
V.ForControl(EditIP).IPAddress(_('IP inválido'));

Faixa numérica

V.ForControl(EditAge)
  .IntegerOnly(_('Apenas números inteiros'))
  .Range(18, 99, _('Idade entre %d e %d'), [18, 99]);

Data + Hora compostas

var DT: TDateTime;
DT := EncodeDateTime(2025,10,10,14,0,0,0);
// Valide cada parte e, se necessário, crie regra custom BetweenDateTimes

Internacionalização (i18n)

Use funções _() para resolver mensagens por idioma e suportar placeholders:

function _(const RS: string): string; overload;        // retorna idioma atual
function _(const RS: string; const Args: array of const): string; overload;

V.ForControl(EditName)
 .MinLen(3, _('Mínimo de %d caracteres'), [3]);

Trocar de idioma = alterar a fonte do _() (dicionário/arquivo/Localizer). Evite concatenação; prefira placeholders.


Feedback Visual e UX

  • Rótulos de erro.WithErrorLabel(LabelXErr)
  • Cores: expose/ou use WithColors(OkColor, ErrorColor) (se disponível) ou trate no OnValidated.
  • Acessibilidade: mensagens curtas, específicas e coerentes por tela.

Performance

  • Debounce embutido no AttachLive para evitar validações excessivas.
  • Regex pré-compiladas e curto-circuito na primeira falha.
  • Cache de RTTI para minimizar overhead.

Erros Comuns & Boas Práticas

  • RadioButtons: garanta um default válido marcado e GroupName consistente. Em cenários dinâmicos, use helpers:
    • AnyRadioChecked(Group): Boolean
    • EnsureAnyChecked(Group, DefaultRadio) após ocultar/mostrar opções
  • ComboBox com placeholder: use RequireNonFirst para impedir o “Selecione…”.
  • ListBox checada: valide quantidade com MinSelected/MaxSelected.
  • Máscaras: quando o backend exige formato estrito, combine Mask + Pattern.
  • Eventos: o Validator4D injeta handlers preservando os originais.

Extensibilidade

  • Regras custom via .Custom(...).
  • Novos controles: implemente métodos de obtenção/definição de valor.
  • Máscaras: estenda padrões conforme necessidade.

FAQ

Valido antes ou depois do LiveBindings?
Geralmente antes de persistir; com AttachOnExit o usuário corrige campo a campo.

Como validar data + hora juntas?
Monte EncodeDateTime e crie uma regra custom BetweenDateTimes.

E se o campo é opcional?
Use WhenFilled: se vazio, demais regras são puladas.


Conclusão

O Validator4D padroniza a validação em FMX com API fluente, i18n e feedback em tempo real opcional. Você ganha consistência, menos código repetido e uma UX melhor — do simples obrigatório até máscaras e regras complexas. Comece pelo Quick Start, cole as Receitas Rápidas e ajuste as mensagens ao seu idioma e domínio.

Próximos passos: adicione um GIF curto mostrando máscara + erro em label; inclua um quadro “Troubleshooting” com mensagens típicas do backend.
Sobre o autor

TheCodeNaked

No TheCodeNaked, programar é consequência, não ponto de partida. Antes do código, vem a dúvida, a análise, o contexto. Não seguimos fórmulas — questionamos. Criar software é pensar com clareza. O resto é só digitação.

TheCodeNaked

Criar com clareza. Codificar com intenção.

TheCodeNaked

Ótimo! Você se inscreveu com sucesso.

Bem-vindo de volta! Você acessou com sucesso.

Você se inscreveu com sucesso o TheCodeNaked.

Sucesso! Verifique seu e-mail para acessar com o link mágico.

As suas informações de faturamento foram atualizadas.

Seu pagamento não foi atualizado