eu estava tentando fazer uma formulário pra inserção de dados em um banco de dados no swing em java, porém estou travado na validação dos dados, eu gostaria que o jFormattedTextField fosse mais específico como aceitar somente um certo número de dígitos (8 pro CEP, por exemplo) e que mostrasse alguma mensagem de erro que somente indicasse os campos errados no próprio formulário sem travar a edição mas que travasse o envio do formulário pro banco de dados…
Eu sou muito iniciante ainda, então qualquer dica é muito bem-vinda!
Olá
Tenta ver sobre listener, mais específico o keylistener ou focuslistener… para sua caixa de
edição.
Guia de referencia da sun, Link1, link2
Espero ter ajudado
Flwsss
T
ton1
vlw thiago, acho q vou usar mto isso^^
mas ainda não sei como começar, na verdade, no caso do campo CEP por exemplo, eu gostaria que não fosse possivel adicionar mais de 8 digitos, então não seria necessário uma mensagem de validação…
O que eu gostaria de saber é se tem como eu verificar o campo assim que ele perder o foco, e, caso necessário, mostar uma mensagem indicado o campo incorreto…
renzonuccitelli
Eu também não curtia a forma de validação do FormatedTextField, então eu construi um textField para validar moeda Real. Acho que dá pra te dar uma idéia de como fazer.
publicclassTextFieldMoedaRealextendsJTextFieldimplementsKeyListener{privateStringBuilderlastValidNumber;privateintmaxDigits=10;/** * Aceita um BigDecimal com escala 2. * Outras escalas não são serão aceitas * * @param BigDecimal */publicvoidsetNumber(BigDecimaldecimal){if(decimal.scale()==2&&decimal.unscaledValue().toString().length()<maxDigits){lastValidNumber=newStringBuilder(decimal.unscaledValue().toString());super.setText(getRealFormat());}}/**Retorna um BigDecimal com o valor encontrando no campo * e com escala igual a 2 * * @return BigDecimal */publicBigDecimalgetNumber(){BigDecimalnumber;if(lastValidNumber.length()==0)number=newBigDecimal("0");elsenumber=newBigDecimal(lastValidNumber.toString());number.setScale(2);returnnumber.divide(newBigDecimal(100));}/**Aceita valor em centavos. * O valor não deve possuir ponto ou vírgula * * @param String */publicvoidsetText(Stringnumber){if(isNumber(number)&&number.length()<maxDigits)lastValidNumber=newStringBuilder(number);elseif("".equals(number))lastValidNumber=newStringBuilder();super.setText(getRealFormat());}privatebooleanisNumber(Stringnumber){for(charc:number.toCharArray()){if(!Character.isDigit(c))returnfalse;}returntrue;}publicTextFieldMoedaReal(){super();this.setCaretPosition(this.getText().length());this.addKeyListener(this);lastValidNumber=newStringBuilder();super.setText(getRealFormat());}@OverridepublicvoidkeyPressed(KeyEvente){}@OverridepublicvoidkeyReleased(KeyEvente){if(Character.isDigit(e.getKeyChar())&&lastValidNumber.length()<maxDigits){lastValidNumber.append(e.getKeyChar());}elseif(e.getKeyCode()==KeyEvent.VK_BACK_SPACE||e.getKeyCode()==KeyEvent.VK_DELETE){if(lastValidNumber.length()>0){lastValidNumber.deleteCharAt(lastValidNumber.length()-1);}}super.setText(getRealFormat());}@OverridepublicvoidkeyTyped(KeyEvente){}privateStringgetRealFormat(){if(lastValidNumber.length()==0)return"0,00";elseif(lastValidNumber.length()==1)return"0,0"+lastValidNumber;elseif(lastValidNumber.length()==2)return"0,"+lastValidNumber;elsereturnbuildPrefixSeparatedWithDots()+lastValidNumber.substring(lastValidNumber.length()-2);}privateStringbuildPrefixSeparatedWithDots(){StringBuilderbuilder=newStringBuilder();for(intindex=0;index<lastValidNumber.length()-2;++index){builder.append(lastValidNumber.charAt(index));if((lastValidNumber.length()-index)%3==0&&lastValidNumber.length()-index>5)builder.append(".");}builder.append(',');returnbuilder.toString();}publicintgetMaxDigits(){returnmaxDigits;}publicvoidsetMaxDigits(intmaxDigits){this.maxDigits=maxDigits;}}
Eu uso Eclipse, não gosto dos códigos que as ferramentas geram para GUI's. Para formulários eu utilizo o SwingBean. Ele já apresenta algumas formas de controle. Contudo, eu alterei o fonte dele para melhorar o uso de máscaras. Isso porque quando vc vai limpar o formulário, o JFormattedTextField apresenta comportamento que eu não gosto. Por isso eu faço com que o usuário não possa deixar o campo se ele não estiver corretamente preenchido ou vazio. Pra isso coloco além da máscara um InputListener e deixo o fild com modo de atuação Persist, em vez de COMMIT. Vai aí o código do meu InputListener, caso vc use a máscara:
Esse InputListener eu tirei do site da SUN e fiz uma pequena alteração para aceitar ficar "vazio".
Como eu disse, eu seto o comportamento do field assim:
textField = new JFormattedTextField(new MaskFormatter(mask));
JFormattedTextField ftf=(JFormattedTextField)textField;
ftf.setInputVerifier(new FormattedTextFieldVerifier(ftf));
ftf.setFocusLostBehavior(JFormattedTextField.PERSIST);
T
ton1
vlw marcius mas essa máscara é ruim pois ela permite a inserção fora de ordem e a validação é limitada tb…
rezo,
cara vc me deu exatamente o que eu queria!!!
eu usei a sua classe pra real como modelo e fiz uma pra CEP, ainda não está perfeita, mas funciona!!
olha o código:
packagelearn;importjava.awt.event.KeyEvent;importjava.awt.event.KeyListener;importjava.math.BigDecimal;importjavax.swing.JTextField;/** * * @author Wellington */publicclassTextFieldCEPextendsJTextFieldimplementsKeyListener{privateStringBuilderlastValidNumber;privateintmaxDigits=8;//<editor-fold defaultstate="collapsed" desc="Sobrescirção dos métodos da implementação 'KeyListener'">@OverridepublicvoidkeyTyped(KeyEvente){}@OverridepublicvoidkeyPressed(KeyEvente){}/*Código executado quando se solta a tecla*/@OverridepublicvoidkeyReleased(KeyEvente){if(Character.isDigit(e.getKeyChar())&&lastValidNumber.length()<maxDigits){lastValidNumber.append(e.getKeyChar());}elseif(e.getKeyCode()==KeyEvent.VK_BACK_SPACE||e.getKeyCode()==KeyEvent.VK_DELETE){if(lastValidNumber.length()>0){lastValidNumber.deleteCharAt(lastValidNumber.length()-1);}}super.setText(getRealFormat());}//</editor-fold>//<editor-fold defaultstate="collapsed" desc="Sobrescrição dos métodos da herança 'JtextField'">publicTextFieldCEP(){super();this.setCaretPosition(this.getText().length());this.addKeyListener(this);lastValidNumber=newStringBuilder();super.setText(getRealFormat());}publicvoidsetNumber(BigDecimaldecimal){if(decimal.scale()==2&&decimal.unscaledValue().toString().length()<maxDigits){lastValidNumber=newStringBuilder(decimal.unscaledValue().toString());super.setText(getRealFormat());}}publicBigDecimalgetNumber(){BigDecimalnumber;if(lastValidNumber.length()==0)number=newBigDecimal("0");elsenumber=newBigDecimal(lastValidNumber.toString());number.setScale(2);returnnumber.divide(newBigDecimal(100));}//</editor-fold>/*Método responsável pela criação da string que será impressa no TextField*/privateStringgetRealFormat(){StringBuilderbuilder=newStringBuilder();if(lastValidNumber.length()==0)return"Digite o CEP";elseif(lastValidNumber.length()<=3)return"-"+lastValidNumber;else{for(intindex=0;index<lastValidNumber.length()-3;++index)builder.append(lastValidNumber.charAt(index));builder.append('-');returnbuilder.toString()+lastValidNumber.substring(lastValidNumber.length()-3);}}}
eu gostaria de deixar uma mensagem quando o campo estiver vazio como ‘Digite o CEP’, mas gostaria que ficasse em uma cor mais clara tipo uma cinza claro ou azul…
eu não entendi o seu 2o post da classe FormattedTextFieldVerifier, vc usa ele pra verificar se todos os campos estão preenchidos?
renzonuccitelli
Eu uso ela pra não deixar a pessoa sair do campo com máscara enquanto ele não estiver corretamente preenchido. Isso porque eu tinha alguns problemas quando ia limpar um formulário no SwingBean.
Mas voltando ao assunto validação, eu li esse tutorial do GUJ, porque gostaria que não aparecessem os caracteres invalidos e depois desaparecessem. Mas ainda nao tive tempo de fazer uns testes. Se vc fizer alguma coisa do gênero, posta aí…
T
ton1
vou dar uma olhada nesse tuto sim
=]
eu tava tentando fazer o TextField pra data de nascimento, mas ao invés dele validar dinamicamente, o que seria complicado pela restrição do dia (que deve ser menor que 32) e mes (menor que 13), eu tava pensando em fazer a validação com a perda de foco, mas não está funcionando…
vc já usou o focuslistener?
a minha tentativa deu nesse código:
packagePrincipal.newFolder;importjava.awt.event.FocusEvent;importjava.awt.event.FocusListener;importjava.awt.event.KeyEvent;importjava.awt.event.KeyListener;importjava.math.BigDecimal;importjavax.swing.JTextField;/** * * @author Wellington */publicclassTextFieldNascimentoextendsJTextFieldimplementsKeyListener,FocusListener{privateStringBuilderlastValidNumber;privateintmaxDigits=8;//<editor-fold defaultstate="collapsed" desc="Sobrescrição dos métodos da implementação 'KeyListener'">@OverridepublicvoidkeyTyped(KeyEvente){}@OverridepublicvoidkeyPressed(KeyEvente){}/*Código executado quando se solta a tecla*/@OverridepublicvoidkeyReleased(KeyEvente){if(Character.isDigit(e.getKeyChar())&&lastValidNumber.length()<maxDigits){lastValidNumber.append(e.getKeyChar());}elseif(e.getKeyCode()==KeyEvent.VK_BACK_SPACE||e.getKeyCode()==KeyEvent.VK_DELETE){if(lastValidNumber.length()>0){lastValidNumber.deleteCharAt(lastValidNumber.length()-1);}}super.setText(getRealFormat());}//</editor-fold>//<editor-fold defaultstate="collapsed" desc="Sobrescrição dos métodos da implementação 'FocusListener'">@OverridepublicvoidfocusGained(FocusEvente){}/*Código executado quando move-se o cursor para outro campo*/@OverridepublicvoidfocusLost(FocusEvente){StringBuilderdia=newStringBuilder();StringBuildermes=newStringBuilder();StringBuilderano=newStringBuilder();if(lastValidNumber.length()==8){for(intindex=0;index<=7;index++){if(index<=1){dia.append(lastValidNumber.charAt(index));}elseif(index>1&&index<=3){mes.append(lastValidNumber.charAt(index));}elseif(index>3&&index<=7){ano.append(lastValidNumber.charAt(index));}}if(Integer.parseInt(dia.toString())>31||Integer.parseInt(mes.toString())>12){lastValidNumber.delete(0,lastValidNumber.length());getRealFormat();}}}//</editor-fold>//<editor-fold defaultstate="collapsed" desc="Sobrescrição dos métodos da herança 'JtextField'">publicTextFieldNascimento(){super();this.setCaretPosition(this.getText().length());this.addKeyListener(this);lastValidNumber=newStringBuilder();super.setText(getRealFormat());}publicvoidsetNumber(BigDecimaldecimal){if(decimal.scale()==2&&decimal.unscaledValue().toString().length()<maxDigits){lastValidNumber=newStringBuilder(decimal.unscaledValue().toString());super.setText(getRealFormat());}}publicBigDecimalgetNumber(){BigDecimalnumber;if(lastValidNumber.length()==0)number=newBigDecimal("0");elsenumber=newBigDecimal(lastValidNumber.toString());number.setScale(2);returnnumber.divide(newBigDecimal(100));}//</editor-fold>/*Método responsável pela criação da string que será impressa no TextField*/privateStringgetRealFormat(){StringBuilderbuilder=newStringBuilder();if(lastValidNumber.length()==0)return"";elseif(lastValidNumber.length()<=4)return""+lastValidNumber;else{for(intindex=0;index<lastValidNumber.length()-3;++index){builder.append(lastValidNumber.charAt(index));if(index!=0&&index%2==1)builder.append('/');}returnbuilder.toString()+lastValidNumber.substring(lastValidNumber.length()-3);}}}
^^
e vc sabe pq tem ‘@Override’ antes dos métodos das interfaces??
desculpa a avalanche de perguntas, mas eu to começando agora e to totalmente a deriva^^
vlw!
renzonuccitelli
Bom, como eu uso o SwingBean ele já coloca um componente gráfico muito legal para datas. Mas se vc não kiser utilizar o framework, eu olhei o fonte e ele usa o componente encontrado nesse link para datas. Dá uma olhada aí.
T
ton1
muito bom o calendário renzo, porém, ele não tem nenhuma validação caso a data seja inserida diretamente no campo, o que permitiria a inserção de datas malucas^^
eu consegui usar o focuslistener! faltava eu colocar this.addFocusListener(this); na sobrescrição do construtor -.-’
iauhsdhasiud
agora ficou bom, ele não permite dias maiores que 31 e nem meses maiores que 12, caso haja, ele apaga todo o campo.
teve um outro efeito que não foi intencional, quando vc aperta DELETE ou BACKSPACE ele apaga todo o campo ao invés de apagar somente um caractere, mas eu achei melhor assim, pq antes vc tinha que apertar um DELETE pra cada char^^
testa o codigo ae:
packagePrincipal.newFolder;importjava.awt.event.FocusEvent;importjava.awt.event.FocusListener;importjava.awt.event.KeyEvent;importjava.awt.event.KeyListener;importjava.math.BigDecimal;importjavax.swing.JTextField;/** * * @author Wellington */publicclassTextFieldNascimentoextendsJTextFieldimplementsKeyListener,FocusListener{privateStringBuilderlastValidNumber;privateintmaxDigits=8;//Sobrescrição dos métodos da implementação 'KeyListener'@OverridepublicvoidkeyTyped(KeyEvente){}@OverridepublicvoidkeyPressed(KeyEvente){}/*Código executado quando se solta a tecla*/@OverridepublicvoidkeyReleased(KeyEvente){if(Character.isDigit(e.getKeyChar())&&lastValidNumber.length()<maxDigits){lastValidNumber.append(e.getKeyChar());}elseif(e.getKeyCode()==KeyEvent.VK_BACK_SPACE||e.getKeyCode()==KeyEvent.VK_DELETE){if(lastValidNumber.length()>0){lastValidNumber.deleteCharAt(lastValidNumber.length()-1);}}super.setText(getRealFormat());}//Sobrescrição dos métodos da implementação 'FocusListener'@OverridepublicvoidfocusGained(FocusEvente){}/*Código executado quando move-se o cursor para outro campo*/@OverridepublicvoidfocusLost(FocusEvente){VerificaCampo();}//Sobrescrição dos métodos da herança 'JtextField'publicTextFieldNascimento(){super();this.setCaretPosition(this.getText().length());this.addKeyListener(this);this.addFocusListener(this);lastValidNumber=newStringBuilder();super.setText(getRealFormat());}publicvoidsetNumber(BigDecimaldecimal){if(decimal.scale()==2&&decimal.unscaledValue().toString().length()<maxDigits){lastValidNumber=newStringBuilder(decimal.unscaledValue().toString());super.setText(getRealFormat());}}publicBigDecimalgetNumber(){BigDecimalnumber;if(lastValidNumber.length()==0)number=newBigDecimal("0");elsenumber=newBigDecimal(lastValidNumber.toString());number.setScale(2);returnnumber.divide(newBigDecimal(100));}/*Método responsável pela criação da string que será impressa no TextField*/privateStringgetRealFormat(){StringBuilderbuilder=newStringBuilder();if(lastValidNumber.length()==0)return"";elseif(lastValidNumber.length()<=4)return""+lastValidNumber;else{for(intindex=0;index<lastValidNumber.length()-3;++index){builder.append(lastValidNumber.charAt(index));if(index!=0&&index%2==1)builder.append('/');}returnbuilder.toString()+lastValidNumber.substring(lastValidNumber.length()-3);}}privatevoidVerificaCampo(){StringBuilderdia=newStringBuilder();StringBuildermes=newStringBuilder();StringBuilderano=newStringBuilder();if(lastValidNumber.length()==8){for(intindex=0;index<=7;index++){if(index<=1){dia.append(lastValidNumber.charAt(index));}elseif(index>1&&index<=3){mes.append(lastValidNumber.charAt(index));}elseif(index>3&&index<=7){ano.append(lastValidNumber.charAt(index));}}if(Integer.parseInt(dia.toString())>31||Integer.parseInt(mes.toString())>12){lastValidNumber.delete(0,lastValidNumber.length());for(intindex=0;index<=7;index++)lastValidNumber.append(' ');}super.setText(getRealFormat());lastValidNumber.delete(0,lastValidNumber.length());}}}
renzonuccitelli
Só algumas ressavas:
Se não me engano o componente é setado via classe Date, entao nao vai ter como setar datas inválidas.
Se o seu sistema for bem feito o suficiente, ele não vai deixar uma data mal formada ser inserida no BD, e por isso nunca vai ter data inválida para ser inserida.
Vc poderia fazer sus própria validação na hora de setar
O controle de datas é um pouco mais complexo que nao permitir dias maiores que 31. Há os meses que possuem máximos de dias diferentes e ainda há os anos bissextos.
a validação na hora de setar teria que ser depois do programa ter se comunicado com o banco de dados, não é? Se sim, seria algo mais lento, eu gostaria de uma validação dinamica (no estilo JavaScript) ^^
eu vou tentar fundir os dois, o meu validador, com aquele calendário, mas pra isso eu precisaria de uma forma de informar o erro pro usuário, pq por exemplo, quando ele inserir 29/02/2006, pode ser que ele não perceba que não é ano bissexto e continue tentando até cansar…
vc usa alguma mensagem (além de labels^^) pra informar os erros?
algo assim:
renzonuccitelli
Eu uso as máscaras e estava usando algumas opções do SwingBean para fazer a validação. Mas aí desisti por algumas razões e vou deixar pra fazer a validação de forma não dinâmica mesmo, só depois que o usuário tentar cadastrar. Aí eu coloco o validador pra funcionar e ele retorna as mensagens de erro. Quanto ao fato de setar, ele não precisa ir pro BD não. Ele passa para pela camada de validação antes, então se ele não passar pelos testes vc lança a mensagem de erro antes de haver interação com o BD.
Com relação ao componente, ele já mostra os dias disponíveis da semana, inclusive mostrando os dias da semana em que caem os dias, o que eu acho interessante. Mas enfim, cada usa o que acha melhor.