Máscaras de Data no Delphi

por Eduardo Rocha - Publicado em 14/06/10

Não sei se é uma "falha" do Delphi ou minha :), pois nunca conseguir resolver uma situação simples:

"Permitir que o usuário limpe o conteúdo de um DBEdit se o campo estiver com máscara de Data na propriedade EditMask".

Faça você mesmo o teste. Inicie um projeto do zero, adicione um ClientDataSet e no FieldsEditor crie um campo do tipo Date.

Neste campo ajuste a propriedade EditMask usando aquela máscara de data sugerida pelo próprio Delphi no Editor de Mascara: "!99/99/00;1;_". Em seguida ajuste também o DisplayFormat para "dd/mm/yy".

Agora volte ao formulário e adicione um DataSource ligando-o no ClientDataSet. Adicione também um DBEdit ligando-o no DataSource e no campo Data recém criado.

Para realizarmos os testes precisamos conseguir "sair" do DBEdit, ou seja, perder o foco, portanto, coloque qualquer componente que receba foco ao lado do DBEdit, pode ser um Edit, por exemplo.

No evento OnCreate do formulário apenas crie o ClientDataSet em memória:

procedure TForm1.FormCreate(Sender: TObject);
begin
  ClientDataSet1.CreateDataSet;
end;

Execute a aplicação e no DBEdit digite uma data qualquer em seguida aperte o TAB.

Legal, nenhuma mensagem apareceu e o foco foi para o Edit.

Agora volte ao DBEdit e apague a data. Em seguida tente sair do campo, veja a mensagem que aparece:

Por que isso?

No help do Delphi diz que o caractere "0" nos obriga a termos um valor numérico naquela posição, enquanto que o caractere "9" não obriga.

Analisando a máscara de data sugerida pelo Delphi temos:

!99/99/00;1;_

Veja os dois caracteres "0" (zero) no final, ou seja, somos obrigados a preencher os dois últimos dígitos (ano) da data, por isso a mensagem anterior é exibida quando tentamos limpar o campo.

Só não consegui entender por que a máscara padrão usou "0" somente no ano :)

Bom, então é simples, basta trocar o "00" por "99" correto?

Vamos lá, faça este ajuste na máscara deixando-a assim:

!99/99/99;1;_

Agora repita o mesmo teste, ou seja, preencha a data no campo e depois tente apagar e sair do campo e veja uma nova mensagem:

Mas por que isso?

Debugando descobri que isso acontece por que ao limparmos o DBEdit, o que de fato está tentando ser "gravado" no campo é " / / " e isso realmente não é uma data válida, por isso a mensagem de "data inválida" é exibida. Inclusive desta vez é o TField quem está alertando e não mais o TDBEdit devido à máscara.

Bom, a solução que encontrei foi ajustar o evento OnSetText do campo para checar, se estiver recebendo este valor, simplesmente limpa o campo, caso contrário define o valor que está recebendo.

Portanto, abra o FieldsEditor do ClientDataSet e no evento OnSetText deste campo codifique da seguinte forma:

procedure TForm1.ClientDataSet1DATASetText(Sender: TField;
  const Text: String);
begin
  if Trim(Text) = '/  /' then
    Sender.Clear
  else
    Sender.AsString := Text;
end;

Pronto, agora pode fazer os mesmos testes e verá que o problema está solucionado.

Bom, este problema sim, mas esqueci de falar de um outro.

Faça o seguinte teste: digite a data 01/01/01 no dbedit (o objetivo é ter diversos zeros). Em seguida saia do campo e entre novamente, veja o que acontece:

No dia e no mês, onde deveria aparecer o zero ficou aparecendo o "_", por que será?

Boa pergunta, também não entendi. Mas a solução que adotei foi implementar um código no evento OnGetText do campo da seguinte forma:

procedure TForm1.ClientDataSet1DATAGetText(Sender: TField;
  var Text: String; DisplayText: Boolean);
begin
  if not Sender.IsNull then
    Text := FormatDateTime('dd/mm/yy', Sender.AsDateTime)
  else
    Text := '';
end;

Pronto, agora sim tudo funciona perfeitamente!

Bom, é isso, queria deixar esta dica aqui, mas se alguém tiver uma solução mais simples, please, me diga, pois como disse no início, não sei se é uma "falha" do nosso amigo Delphi ou minha!

Abraços

7 Comentários

  • Pablo Carvalho - 16/06/10 09:01

    Eduardo, acredito que o problema dos Zeros possa se resolver trocando o "_" por "0" na máscara ("!99/99/99;1;0"), assim você indica que o caracter assumido na falta de digitação é o zero, e com isso grava a data corretamente.

    Parabéns pelo artigo.

  • Eduardo Rocha - 16/06/10 09:15

    Pablo,

    Agradeço pela ajuda, mas testei o que você disse e gerou um outro problema.

    Entre com a data "20/11/82", por exemplo, ele troca o "20" por "02".

    Quem tiver outra dica, pode mandar!

    Obrigado

    Abs

  • Jean - 16/06/10 09:30

    Sua solução funciona, mas isso pode ser muito trabalhoso se considerarmos que utilizamos data no sistema todo, e ainda pode ocorrer de esquecermos de codificar o evento OnSetText de algum field.
    Para solucionar este problema adotei o component JvDBDateEdit da biblioteca Jedi, que resolve este problema e é muito útil para o usuário final utilizar.

  • Eduardo Rocha - 16/06/10 09:35

    Jean,

    Muito obrigado pela sua dica, certamente usar um componente que já faça todo "trabalho" é muito mais prático.

    Abs

  • Pablo Carvalho - 16/06/10 10:19

    Tem razão, na minha sugestão anterior as datas que terminavam com zero ficavam erradas.

    Consegui uma solução alterando o EditMask para !99/99/99;1;0 e o evento onSetText por:

    if Trim(Text) = '/ /' then
    Sender.Clear
    else
    Sender.AsString := StringReplace(Text, ' ', '0', [rfReplaceAll]);

    Dessa maneira não é preciso codificar o evento onGetText.

  • Eduardo Rocha - 16/06/10 10:32

    Pablo,

    Agora funcionou, o único "inconveniente" é que ao entrar no campo fica "00/00/00" caso não haja uma data preenchida.

    Mas funcionou.

    Obrigado

    Abs

  • Vladimir Sousa - 20/07/10 12:33

    Eduardo testei a sua solução e Funcionou perfeitamente, havia 3 semanas que procurava na internet e não encontrava.

    procedure TForm1.ClientDataSet1DATASetText(Sender: TField;
    const Text: String);
    begin
    if Trim(Text) = '/ /' then
    Sender.Clear
    else
    Sender.AsString := Text;
    end;

    Você salvou meu dia, muito obrigado.

 

"Ouvindo" Opiniões (as mais lidas)

Em breve, aguarde!!!

Pharetra Sed Tempus

Morbi sit amet mauris Nam vitae nibh eu sapien dictum pharetra. Vestibulum elementum neque vel lacus. Lorem ipsum dolor sit dolore phasellus pede lorem proin auctor dolor loremmassa phasellus sit. More…

Outras edições da Revista Active Delphi