Máscaras de Data no Delphi
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.










