Binding a JTextField e poder limitar comprimento

31 respostas
tebosoftware

Boa noite pessoal

Gostaria de saber se alguém sabe como limitar o comprimento do String dentro de JTextField, so que o mesmo está Binding (vinculado) a uma propriedade de um objeto?

Eu até desenvolvi uma classe que implementa o Document para fazer isso, só que quando o Bean Binding é inicializado, ele substitui o meu Document.

desde já agradeço

31 Respostas

tebosoftware

Bom dia pessoal?

alguém utiliza por acaso Beans Binding neste forum?

grato

Marky.Vasconcelos

Voce que criou esse Document para o binding? se for…

Coloque o limitador nele mesmo.

tebosoftware

Eu até coloco esse document,
so que o binding substitui pelo dele

Marky.Vasconcelos

Então… mas voce que criou esse Document para Binding?

Por que voce não pega o Document do JTextField depois do binding substitui-lo e coloca seu limitador nele?

tebosoftware

Mas o Binding necessita do Document dele para controlar a transferencia dos valores.

Marky.Vasconcelos

Não to falando pra substituir.
To falando pra adicionar sua lógica de limitação nele.

tebosoftware

Mas como?

O binding é feito atraves de um Factory e eu não sei qual classe ele utiliza para fazer isso.

vou tentar achar a classe q é montada.

ou existe outra maneira?

Marky.Vasconcelos

Ahh… eu pensei que voce tinha feito essa classe…

Mas…

Voce pode pegar o Document do JTextField e adicionar um DocumentListener nele com essa lógica.

Marky.Vasconcelos

Depois do binding pegue o Document e adicione algo assim…

textField.getDocument().addDocumentListener(new DocumentListener(){
//Lógicas aqui
public void insertUpdate(DocumentEvent e){
}
public void removeUpdate(DocumentEvent e){
}
public void changedUpdate(DocumentEvent e){
}
});

PS: Eu nunca precisei fazer isso só to pesquisando na API e te falando.

http://java.sun.com/j2se/1.3/docs/api/javax/swing/JTextField.html
http://java.sun.com/j2se/1.3/docs/api/javax/swing/text/Document.html
http://java.sun.com/j2se/1.3/docs/api/javax/swing/event/DocumentListener.html
http://java.sun.com/j2se/1.3/docs/api/javax/swing/event/DocumentEvent.html

tebosoftware

Boa Ideia cara

muito obrigado, não tinha reparado que tinha listeners no Document.

grato e desculpe qualquer coisa

tebosoftware

Tentei montar o travamento no evento insertUpdate do listenner DocumentListener, só que não deu muito certo não pois ele nao tem retorno de validação e tb não funciona com exception.

fiz assim:

new DocumentListener() {

            public void insertUpdate(DocumentEvent e) {
                if (!(e.getDocument().getLength() < EstadoController.LENGTH_SIGLA &&
                        e.getDocument().getLength() + e.getLength() < EstadoController.LENGTH_SIGLA)){
                    throw new IllegalArgumentException();
                }
            }

            public void removeUpdate(DocumentEvent e) {
                
            }

            public void changedUpdate(DocumentEvent e) {
                
            }
        }

e a documentação fala que o document é imutavel durante o evento por ser threadsafe.

teria alguma sugestão?

tebosoftware

Achei esta documentação que ajudou muito a montar o q eu queria.

https://java.sun.com/docs/books/tutorial/uiswing/components/generaltext.html#doclisteners

falow

tebosoftware

Afff… quase deu certo.

descobri que a classe que o beanbinding altera tb é o DocumentFilter com a classe JTextComponentAdapterProvider
aff… vou ter que estudar mais um pouco e terei q alterar essa classe tb…
aff
rs

Marky.Vasconcelos

Nossa… mas continue com os estudos que no final voce consegue.

tebosoftware

Mark

estive estudando o componente BeansBinding e ele tem uma classe que valida os dados que são inseridos, e tem tb um listener para que possa ser feito alguma coisa.

no meu caso no validator, coloquei para retornar um erro quando for superior a quantidade de caracteres, utilizando a classe Result do BeansBinding.

e Adicionei um listener e no evento de falha de sincronismo eu mostro uma mensagem.

A validação funciona pois não altera o Bean que estou vigiando, so que visualmente não funciona pois o JTextField ainda continua exibindo os caracteres que passaram do limite.
vc ja trabalhou com o BeansBindig?

Se não trabalhar, como vc faz a vinculação dos componentes swing com os beans?

grato

Marky.Vasconcelos

Então… no meio dos meus projetos eu acho que reinventei varias rodas então eu uso um objeto que eu mesmo criei…

Chamo de ComponentBind passo JTextComponents e FieldResovers para ele e quando for atualizer o objeto eu faço

binder.updateObject(objectDoTipo);

E para atualizar a view chamo o método assim:

binder.updateView(objectDoTipo);
tebosoftware

Você utiliza então uma idéia de MVC ou MVP?

Marky.Vasconcelos

Sinceramente não sei xD

Eu separo assim:

model > models
dao > DAO generica e conexao com banco
view > Swing

Eu ligo o model com a view atraves do Binder que criei
E uso a dao para mandar pro banco.

Eu acho que é MVC.

Eu não estudei MVC e MVP.

tebosoftware

Em que momento vc faz a validação dos dados?

Marky.Vasconcelos

Então… é que todos os campos Strings no meu bd estão como varchar<255> então não me preocupo com o tamanho, os campos ints e doubles são convertidos pelo binder e caso tenha algo errado (Por exemplo letras) ele lança uma Exception que eu posso tratar para validação.

E tem outra coisa meu Binder não mantem sincronizado os dois… apenas quando chamo os métodos para atualizar ou a view com o objeto ou o objeto com a view eu sei os valores.

tebosoftware

Eu quis dizer em relação a validação de valores, como se um campo de percentual aceita uma determinada faixa, etc

Marky.Vasconcelos

Todos meus campos não tem essas exigencias… mas de qualquer modo no conversor do binder seria possivel de colocar isso… por que ao converer o valor poderia lançar uma Exception.

tebosoftware

Acho q não está me entendendo

quando um campo exige um determinado valor tipo, quantidade não pode ser inferior a 1, essa validação vc faz no view, ou vc faz no model?

Marky.Vasconcelos

Então… voce que não me entendeu

No meu binder eu tenho a opção de passar um formatter meu que a interface é a seguinte

public interface Formatter{
public Object parseString(String arg1);
public String format(Object obj1);
}

Caso o método retorne uma Exception eu lanço ela ao método que chamou o update do binder.

Tipo assim:

Formatter valorMaiorQueUm = new Formatter(){
@Override
public String format(Object obj1){
return Integer.toString((Integer)obj1);//Eu sei que nessa coluna ele retorna sempre Integers
}
@Override
public Object parseString(String arg1){
int obj;
try{
obj = Integer.parseInt(arg1);
}catch(Exception e){
throw new RuntimeException(arg1+": Este valor não é um numero inteiro valido");
}

if(obj < 1)
throw new RuntimeException(arg1+": O valor não pode ser menor que um");

return obj;
}
}
tebosoftware

O problema que eu encontro nesta abordagem é que o usuários só vai saber que deu erro quando é feito a transferência de dados, depois que ele já preencheu toda a tela.

Marky.Vasconcelos

É… eu sei disso…

Mas mes campos não precisam de validação desse tipo, apenas para converter para numeros alguns valores.

Mas pretendo fazer algo para validar mesmo, tava pensando nisso a um tempo.

Marky.Vasconcelos

E eu não sei se é tão ruim assim quando o usuario processa os dados aparece um campo em vermelho pois está com algo errado.

tebosoftware

Bom num sistema baseado na web, geralmente a validação é feita somente no retorno, mas numa aplicação desktop, acredito que o usuário tenha que saber antes pois ele, em geral, espera mais agilidade numa aplicação desktop.

Marky.Vasconcelos

E o engraçado é que tenho um sistema na web para um cliente com JSF e a validação é na hora.
=/

Mas eu pretendo implementar algo em breve com essa finalidade para meus sistema desktop.

tebosoftware

Bom eu estou estudando o beansbinding e com ele posso colocar validators, que impedem que seja colocado um valor inválido, e tb coloquei um extended by org.jdesktop.beansbinding.AbstractBindingListener no metodo syncFailed e nele eu faço o bind efetuar um refresh ai ele restaura o último valor válido. E parece que ficou legal.
Vou testar mais e ver se existe outras maneiras.

falow

root_

EStou com o mesmo problema que vc tebosoftware, criei uma classe bacaninha extendendo o document… onde passo por parametros a quantidade de caracteres que o textField vai aceitar, se é tudo Upper ou Lower e se é alfanuméricou ou numérico.
O problema é quando uso binding no textField… pois perde toda formatação do document que eu havia criado…

Você já conseguiu uma solução razoável para isso???

Minha FixedLengthDocument

public class FixedLengthDocument extends PlainDocument
{
    private int limit = -1;
    private int fixedLengthDocumentMode = -1;
    private ArrayList&lt;String&gt; noInsertCharsVerify = new ArrayList&lt;String&gt;();
    private String[] listNoInsertChars = new String[]{};
    public static final int LENGTH_UNLIMITED = -1;

    public static final int TO_UPPER = 1;
    public static final int TO_LOWER = 0;
    public static final int TO_DEFAULT = -1;
    /**
     *
     * @param maxlen
     */
    public FixedLengthDocument(int limit)
    {
        super();
        this.limit = limit;
        this.fixedLengthDocumentMode = TO_DEFAULT;
        this.listNoInsertChars = new String[]{};
        this.noInsertCharsVerify = new ArrayList&lt;String&gt;();
    }
    public FixedLengthDocument(int limit, int fixedLengthDocumentMode)
    {
        super();
        this.limit = limit;
        this.fixedLengthDocumentMode = fixedLengthDocumentMode;
        this.listNoInsertChars = new String[]{};
        this.noInsertCharsVerify = new ArrayList&lt;String&gt;();
    }
    public FixedLengthDocument(int limit, int fixedLengthDocumentMode, String[] listNoInsertChars)
    {
        super();
        this.limit = limit;
        this.fixedLengthDocumentMode = fixedLengthDocumentMode;
        this.listNoInsertChars = listNoInsertChars;
        System.out.println("listNoInsertChars:" + listNoInsertChars.length);
        this.noInsertCharsVerify = new ArrayList&lt;String&gt;();
        for(int i=0; i&lt;listNoInsertChars.length; i++)
            this.noInsertCharsVerify.add(listNoInsertChars[i]);
    }

    @Override
    public void insertString(int offset, String str, AttributeSet attr)
                    throws BadLocationException
    {
        if(!noInsertCharsVerify.isEmpty())
            for( int i = 0; i &gt;&lt; str.length(); i++ )
                if(noInsertCharsVerify.contains( String.valueOf(str.charAt(i))) )
                    return;
        if((limit&gt;LENGTH_UNLIMITED) && (getLength() + str.length()) &lt;= limit)
        {
            switch(fixedLengthDocumentMode)
            {
                case TO_UPPER:
                    super.insertString(offset, str.toUpperCase(), attr);
                break;
                case TO_LOWER:
                    super.insertString(offset, str.toLowerCase(), attr);
                break;
                case TO_DEFAULT:
                    super.insertString(offset, str, attr);
                break;
            }
        }
        else
        {
            if(limit ==LENGTH_UNLIMITED)
            {
                switch(fixedLengthDocumentMode)
                {
                    case TO_UPPER:
                        super.insertString(offset, str.toUpperCase(), attr);
                    break;
                    case TO_LOWER:
                        super.insertString(offset, str.toLowerCase(), attr);
                    break;
                    case TO_DEFAULT:
                        super.insertString(offset, str, attr);
                    break;
                }
            }
        }
    }

    @Override
    public void remove(int offs, int len) throws BadLocationException
    {
        super.remove(offs, len);
    }
}
Criado 3 de dezembro de 2008
Ultima resposta 4 de abr. de 2011
Respostas 31
Participantes 3