Formatando

Galera é o seguinte, eu tenho jtextfield e quero formatá-lo para receber uma data (exemplo: 01/05/2010). Só que além disso quero que ele formate de acordo com o que a pessoa for digitando, por exemplo, a pessoa digita:

120

depois que ela digitar o zero aparece a primeira barra, ficaria assim:
12/0

… seguindo a pessoa digita:
12/082

depois que ela digitar o dois aparece a segunda barra…
12/08/2

e o resto
12/08/2010.

tem um exemplo no link que vou colocar, só que é em java script e eu num entendi nada do que o cara fez. Vou colocar uma parte do código e o link para vocês entenderem melhor:

http://www.mukirana.com/ , vai em cadastre-se e lá tem um exemplo do que eu to falando, mas não com data e sim com CPF e CEP.

parte do código:

[code]
function mask_cpf(v){
v=v.replace(/\D/g,"");
v=v.replace(/(\d{3})(\d)/,"$1.$2");
v=v.replace(/(\d{3})(\d)/,"$1.$2");
v=v.replace(/(\d{3})(\d{1,2})$/,"$1-$2");
return v;
}

//depois ele chama ela assim:

onkeydown="mask(this,mask_cpf);

[code]

Se alguém souber fazer isso em java e puder me ajudar eu agradeço.
Obs.: já falaram para mim usar o jformattextfield, mas não consegui fazer o que eu quero, além de dizer que ele (jformattextfield) é chato pra caramba…

Boa noite Davi.Jv

Que tal usar MaskFormatter e JFormattedTextField fazendo assim:

  try {
        MaskFormatter mask = new MaskFormatter("##/##/####");
        mask.setPlaceholder("_");
  } catch (Exception ex){
        JOptionPane.showMessageDialog(null, ex.getMessage());
  }
  JFormattedTextField data = new JFormattedTextField(mask);

Detalhe é que sua máscara ficará com a formatação assim: “//____”, contudo basta somente digitar os números.

discorpio, já tentei fazer isso, funciona beleza, só que não do jeito que eu quero.
Desse jeito ai as barras ficam aparecendo antes mesmo da pessoa digitar algo, e não é assim que eu quero. eu quero que ela vai aparecendo de acordo com o que a pessoa digita, mas se não tiver jeito eu vou recorrer a esse seu exemplo.

Boa noite Davi

Neste caso podemos também improvisar isso em java.

Basta que voce utilize o evento KeyListener do componente JTextField desta forma:

        txtdata = new JTextField();
        txtdata.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e){
                JTextField text = (JTextField)e.getSource();
                if (text.getText().length() == 2 || text.getText().length() == 5){
                    text.setText(text.getText() + "/");
                }
            }
        });

discorpio, o seu código funcionou beleza, só que se a pessoa errar a data e for tentar corrigir o negócio bagunça tudo. Testa ai pra você ver.
Acontece o seguinte:

Você digita a data normal
10/10/2010

vamos supor que ela (pessoa) queria colocar 11/10/2010,

se ela apagar para poder arrumar, ela não irá conseguir. Depois que apagasse o 2 e a barra ela não consegue apaga o resto, e vira uma confusão. Se você for pro inicio da jtextfield tentar apagar usando o del, ele insere uma barra no final e etc.
acaba que no final se você tentar apagar todos os numeros vai ficar um bocado de barra ( ////// ) no jtextfield.

Mas do mesmo jeito muito obrigado, vou ver se consigo fazer algo para ver se ele para com essa locura.

Caso você ou outra pessoa tenha a solução ( para esse problema que surgiu) e quiser postar ai eu agradeço.

Boa tarde Davi.Jv.

Como disse antes, apenas fiz de improviso e na hora, porém existem também a questão de se limitar a quantidade caracteres para 10 e também a validação das datas.

Assim sendo, quanto a questão de se limitar a quantidade de caracteres no JTextField, necessário é que voce crie a seguinte classe:

import javax.swing.text.*;

public class FixedLengthDocument extends PlainDocument {
    private int iMaxLength;

    public FixedLengthDocument(int maxlen) {
        super();
        iMaxLength = maxlen;
    }

    @Override
    public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
        if (str == null) {
            return;
        }

        if (iMaxLength <= 0)        // aceitara qualquer no. de caracteres
        {
            super.insertString(offset, str, attr);
            return;
        }

        int ilen = (getLength() + str.length());
        if (ilen <= iMaxLength)    // se o comprimento final for menor...
            super.insertString(offset, str, attr);   // ...aceita str
    }

}

Após criar essa classe, configure o seu JTextField assim:

txtdata = new JTextField();
txtdata.setDocument(new FixedLengthDocument(10));

Agora vamos a questão da validação das datas, criando o seguinte método booleano dentro da própria classe onde está o JTextField:

public Boolean validaData(String datatemp){
        Boolean ret;
        String data = datatemp.replace("/","");
        int dia = Integer.parseInt(data.trim().substring(0,2));
        int mes = Integer.parseInt(data.trim().substring(2,4));
        int ano = Integer.parseInt(data.trim().substring(4,8));
        int ultimoDiaMes[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
        if (ano < 1900){
            ret = false;
        } else if (mes < 0 || mes > 12) {
            ret = false;
        // Ano Bisexto    
        } else if (mes == 2 && ultimoDiaMes[mes] == 29 && (ano % 400 > 0 && (ano % 4 > 0 && ano % 100 == 0))){
            ret = false;
        } else if (dia < 0 && dia > ultimoDiaMes[mes]){
            ret = false;
        } else {
            ret = true;
        }
        if (ret == false) JOptionPane.showMessageDialog(null, "Data inválida");
        return ret;
    }

Agora dentro do evento KeyListener, vamos eliminar as barras duplas, assim:

txtdata = new JTextField();
txtdata.setDocument(new FixedLengthDocument(10));
txtdata.addKeyListener(new KeyAdapter() {
      @Override
       public void keyPressed(KeyEvent e){
                JTextField text = (JTextField)e.getSource();
                if (text.getText().length() == 2 || text.getText().length() == 5){
                    if (e.getKeyChar() == '/') {
                        text.getText().replaceAll("//", "/");
                    } else {
                       text.setText(text.getText() + "/");
                    }
                } else if (text.getText().length() == 10){
                    if (!validaData(text.getText())) text.setText("");
                }
        }
});

discorpio, o código deu certo porém continua com o erro que eu havia dito.
erro:
a pessoa digita uma data (exemplo 20/10/2009);

suponhamos que ela digitou a data errada, ela queria digitar (10/09/2009);

quando a pessoa tentar apagar a data (20/10/2009) que ela havia digitado, ela não consegue.

Ela só vai conseguir apagar até o 2 do ano 2009, ficando assim:
20/10

se ela tentar apagar o resto ela não consegue, e se ir para o inicio e tentar apagar do inicio pro fim tbm não dá certo, ele incrementa uma barra no final, ficando assim:
20/10/

a pessoa só vai conseguir apagar a data se selecionar tudo e apagar.

fora isso o código ficou show, mais uma vez muito obrigado, vou dar uma estuda no código para ver se entendo melhor ele e tentar descobrir com consertar isso.

Se você ou outra pessoa souber como consertar, fique a vontade.

Só aproveitando o seu código, teria alguma forma de a mensagem do JoptionPane aparecer logo que o campo data perdesse o foco?
Como ficaria o código?

Boa tarde Davi.

Me desculpe a demora, porém só agora tive tempo de rever o código.

Realmente o código está com um erro de lógica, que quando voce pressiona barra normal repetidas vezes ele não se apaga, então neste caso vamos configurar o JTextField para ser digitado somente números e quando chegar nos índices 2 e 5 e colocar a barra normal automaticamente, e quando for pressionado qualquer outra tecla ele apague automaticamente, inclusive a barra normal, até mesmo dentro dos índices 2 e 5, isto porque ele já vai colocar automaticamente.

Outra coisa que eu pude perceber, de que o evento KeyReleased e melhor do que KeyPressed, na verdade o KeyPressed representa o KeyDown enquanto que o KeyReleased, o KeyUp, então vamos mudá-lo também, em resumo o seu código ficaria assim:

txtdata.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e){
                JTextField text = (JTextField)e.getSource();
                if (Character.isDigit(e.getKeyChar())){
                    if (text.getText().length() == 2 || text.getText().length() == 5){
                        text.setText(text.getText() + "/");
                    } else if (text.getText().length() == 10){
                        if (!validaData(text.getText())) text.setText("");
                    }
                } else {
                    text.setText(text.getText().substring(0, text.getText().length() -1));
                }
            }
 });

Quanto a mensagem só aparecer quando o JTextField perder o foco, neste caso voce terá que configurar da mesma forma com o código acima, os eventos FocusListener, podendo até deixar a mensagem de "Data inválida" dentro do método validaData, e utilizá-lo para retornar o foco para o JTextField editado. Em resumo, o seu código todo ficaria assim:

txtdata.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e){
                JTextField text = (JTextField)e.getSource();
                if (Character.isDigit(e.getKeyChar())){
                    if (text.getText().length() == 2 || text.getText().length() == 5){
                        text.setText(text.getText() + "/");
                    }
                } else {
                    if (text.getText().length() > 0){
                       text.setText(text.getText().substring(0, text.getText().length() -1));
                    }
                }
            }
 });
 txtdata.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e){
                JTextField text = (JTextField)e.getSource();
                if (!validaData(text.getText())){
                    text.setText("");
                }
            }
});

Contudo, se eu fosse voce eu preferiria não implementar esse FocusListener, ficaria com o primeiro código utilizando apenas o KeyListener, porque tentei setar o foco novamente ao JTextField editado, e estava dando erro, e caso de nós pesquisarmos mais.

Um abraço.

discorpio, o código faz exatamente ao contrario do que é pra fazer. Tipo, ele deixa que eu tecle apenas caracteres e não números.

 txtdata.addKeyListener(new KeyAdapter() {  
             @Override  
             public void keyReleased(KeyEvent e){  
                 JTextField text = (JTextField)e.getSource();  
                 if (Character.isDigit(e.getKeyChar())){  
                     if (text.getText().length() == 2 || text.getText().length() == 5){  
                         text.setText(text.getText() + "/");  
                     } else if (text.getText().length() == 10){  
                         if (!validaData(text.getText())) text.setText("");  
                     }  
                 } else {  
                     text.setText(text.getText().substring(0, text.getText().length() -1));  
                 }  
             }  
 }); 

A respeito do que você falou de perde o focus vou manter o código de antes.

Boa noite Davi.

Eu modifiquei a última linha, assim:

txtdata.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e){
                JTextField text = (JTextField)e.getSource();
                if (Character.isDigit(e.getKeyChar())){
                    if (text.getText().length() == 2 || text.getText().length() == 5){
                        text.setText(text.getText() + "/");
                    } else if (text.getText().length() == 10){
                        if (!validaData(text.getText())) text.setText("");
                    }
                } else {
                    // Aqui foi acrescentado esta verificação.
                    if (text.getText().length() > 0){   
                       text.setText(text.getText().substring(0, text.getText().length() -1));   
                    }                 
               }
            }
 });

Esse código só permite a digitação de números.