Data Binding é um processo que estabiliza uma conexão entre uma aplicação User Interface(JFrame) e a lógica do negócio. Se as configurações e notificações estiverem corretas, o Data Binding reflete as mudanças que elas fazem. Vamos supor que temos um AlunoFrame e nela um componente JTextField tNome, também temos a classe Aluno com o getNome e setNome. Se nós aplicarmos o Data Binding vamos fazer que quando seja digitado algo no TextField nome, automaticamente o setNome vai receber o que foi escrito, eles ficam sincronizados, as mudanças que ocorrem no nome ocorrem também no setNome e vice-versa. Mas então tu podes pensar, "por que não usar um setNome neste TextField?".
public class AlunoFrame extends javax.swing.JFrame{ Aluno aluno = new Aluno(); JTextField nome = new javax.swing.JTextField(); /... private void tNomeActionPerformed(java.awt.event.ActionEvent evt){ aluno.setNome(tNome.getText()); }
Podemos ver que fazendo assim não é nem um pouco elegante, deixamos o usuário com muita acessibilidade. Se por acaso ele quiser alterar para setMatricula ele pode, e não é isso que nós queremos. Nós temos que abstrair o usuário sobre o que está acontecendo. E também vale lembrar que para fazer espelhamento, deste modo fica muito "amador". Por isso vamos usar o Data Bindig, agora na prática vai ficar bem mais visível sua utilidade. Então vamos criar uma classe Bind que será a responsável por fazer a sincronização do JFrame com o negócio, so let's go.
public class Bind extends JTextField{ public Bind() { } //criamos um método bind que vai receber os seguintes parametros //obj que será o objeto da classe que queremos alterar //atributo que será qual o atributo da classe que queremos mudar //campoFrame que é o que queremos onde a alteração seja feita //texto é a informação que vamos passar public void bind(Object obj, String atributo, Object campoFrame, String texto) throws NoSuchMethodException, IllegalAccessException...{ //aqui nós vamos ver qual tipo é o campoFrame //e depois repassamos para seu método correspondente if(campoFrame instanceof JTextField){ JTextField tf = (JTextField) campoFrame; bindTextField(obj, atributo, tf, texto); return; } //exemplo com outros tipos de componentes if(campoFrame instanceof JComboBox){ JComboBox cb = (JComboBox) campoFrame; bindComboBoxBinder(obj, atributo, cb, texto); return; } if(campoFrame instanceof JRadioButton){ JRadioButton rb = (JRadioButton) campoFrame; bindRadio(obj, atributo, rb, texto); return; } }Após implementar essa parte, nós precisamos fazer o bindTextField que terá como função ir lá no set da classe do objeto passado e alterar. Essa parte eu admito que é um pouco mais chatinha e complexa de entender pois vamos usar reflections e regex, então vou explicar por partes.
private void bindTextField(Object obj, String atributo, JTextField tf, String texto) throws NoSuchMethodException, IllegalAccessException... { tf.setText(texto); //aqui nós vamos precisar usar reflections para saber os atributos //da classe do objeto que temos Field[] f = obj.getClass().getDeclaredFields(); //criamos um vetor de Field para pegar os atributos Field field = null; //fazemos um for each para pesquisar dentro daquele nosso vetor //para saber pegarmos o atributo que queremos alterar for(Field campo : f){ if(campo.getName().equals(atributo)){ //enquanto a variavel campo não for igual ao atributo continua o for field = campo; //a variavel field recebe o campo quando achado break; } } //agora que já achamos o atributo, nós precisamos encontrar o set dele //ATENÇÃO AGORA //Vamos criar uma String s que irá concatenar a palavra set com //a primeira letra do atributo em maiuscula e o restante em minuscula String s = "set" + field.getName().toUpperCase().charAt(0)+ field.getName().substring(1); //no nosso exemplo fica s = "set"+N+omeDepois que "formamos" o setNome, nós precisamos achar ele nos métodos da classe e fazer a alteração.
String tipo = field.getType().getSimpleName();//aqui criamos uma variavel tipo que irá //pegar o nome do Tipo do campo field(que é nome) Method meth = null; //é criada uma variavel do tipo Method que será usada //para chegar ao método setNome //é feito um switch para ver qual é o Tipo do nosso atributo que será atualizado switch(tipo){ case "String": //meth = aluno.getClass().getMethod(setNome, tipo String); meth = obj.getClass().getMethod(s, String.class); //usamos o metodo invoke para passar o objeto e a nova informação meth.invoke(obj, texto); break; case "int": case "Integer": meth = obj.getClass().getMethod(s,Integer.TYPE); meth.invoke(obj, Integer.parseInt(texto)); break; case "float": case "Float": meth = obj.getClass().getMethod(s,Float.TYPE); meth.invoke(obj, Float.parseFloat(texto)); break; case "double": case "Double": meth = obj.getClass().getMethod(s,Double.TYPE); meth.invoke(obj, Double.parseDouble(texto)); break; case "booelan": Boolean.parseBoolean(texto); break; case "Date": //OBSERVAÇÃO COM O DATE //d{2}dias / d{2} mes / d{4} ano Pattern pattern = Pattern.compile("\\d{2}\\/\\d{2}\\/\\d{4}"); if(pattern.matcher(texto).find()){ SimpleDateFormat data = new SimpleDateFormat("dd/MM/yyyy"); meth = obj.getClass().getMethod(s, Date.class); meth.invoke(obj, data.parse(texto)); } break; } }O case Date vou explicar por aqui pois é o mais complicado deles. Se por caso o nosso aluno tenha dataDeNascimento do tipo Date, vai ser necessário usar regex para formatar a data conforme for configurada pelo usuário, apartir do SimplesDateFormat(esqueçam todas gambiarras feitas até então). Criamos uma variável do tipo Pattern, quando colocamos o d{2} dizemos que aquela parte recebe até dois decimais. Mais a baixo temos um SimplesDateFormat que está separando por dia, mês e ano. Após isso, é igual aos outros.
Aqui terminamos nossa classe Bind, agora vamos ver como usar ela. No nosso formulário, no campo tNome nós precisamos usar o evento KeyReleased, fica da seguinte forma.
private void tNomeKeyReleased(java.awt.event.KeyEvent evt) { Bind t = new Bind(); t.bind(aluno2, "nome", tCampoParaMostrar, tNome.getText()); }
Admito que demorei para pegar a ideia do Data Binding, para entender como funciona essa sincronização via objeto, mas não é complicado de fazer, só é necessário tempo. Sobre reflections e regex, a ideia é bem fácil de entender.