JTable Dinamica!

Olá pessoal, minha duvida é a seguinte eu gostaria de construir uma tela de consulta que funcionasse pra todo o
sistema. Mas para isso eu necessitaria criar uma JTable dinamica que funcionasse genericamente somente com passagem de parametros. Obs: eu trabalho beans. Isso é possivel? Alguem ja fez isso ou pode me ajudar?

grato.

Dê uma olhada na implementação de TableModel presente nesse exemplo:
http://www.guj.com.br/posts/list/100793.java

Você só precisa passar uma lista de colunas para ele. Essa lista pode ser fornecida por parâmetro.

Aliás, você sabe exatamente como funciona o TableModel? Sabe construir um model próprio?
Sem saber isso, fica difícil fazer o que você quer.

Se não sabe, leia os seguintes artigos:
http://www.informit.com/articles/article.aspx?p=332278
http://www.informit.com/articles/article.aspx?p=333472

Obrigado amigo! vou analisar seu codigo. Entendo e sei criar um TableModel

Se vc quer algo bem dinamico vc pode usar annotation para ler o seu bean e montar a jtbale baseado nas propriedades do seu bean.
Eu tenho alguns códigos prontos aqui que eu implementei…se vc quiser eu posso postar ai pra vc.

Abraços.

Se vc postar o codigo ou me mandasse no e-mail josimarsis@gmail.com ficaria muito grato! O meu problema é exatamente pegar os valores dos beans dinamicamente.

Reflection também é interessante… já escrevi um tableModel assim e para construir uma tabela eu preciso fazer apenas algo assim

FieldResolverFactory resolvers = new FieldResolverFactory(Pessoa.class);
ObjectTableModel model = new ObjectTableModel(new FieldResolver[]{
resolvers.create("nome","Nome:"),//1° = nome do campo, 2° = nome da coluna na tabela
resolvers.create("rg"),//o nome do campo é assumido para o nome da coluna
resolvers.create("idade", Formatters.INT_FORMATTER)//Para campos que não sejam String(Se voce quiser apenas mostrar o valor não é nexessario um Formatter mas para atualizar o bean é.
});
JTable table = new JTable(model);
model.setData(dao.getList(Pessoa.class));

Com esse código voce teria uma JTable para a classe Pessoa que mostra o nome, rg e a idade na tabela.

Ainda implementei por Annotation um modo para marcar na classe os valores configuraveis para o FieldResolver.

E ai josimarsis, blz?
Então, eu já li todos esses posts que o ViniGodoy te passou e acho importante vc olhar…além disso seria legal vc entender Reflection(se não conhecer).Segue o exemplo: vamos considerar um exemplo simples:Clientes.

1º passo: vamos criar uma annotation - depois explico melhor sobre ela.

[code]import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Coluna {
//vamos utilizar esta annotation para pegar o nome da coluna,posicao no jtable e o formato que queremos mostrar - vamos usar com uma data
//como exemplo.
String nome();
int posicao();
String formato() default “%s”;

}[/code]

2º passo:vamos criar o bean com as annotation:

[code]import java.util.Calendar;

public class ClienteBean {
private Integer codigoCliente;
private String nomeCliente = “”;
private String cpf = “”;
private Calendar dataNascimento;

public void setCodigoCliente(Integer codigoCliente) {
    this.codigoCliente = codigoCliente;
}

public void setCpf(String cpf) {
    this.cpf = cpf;
}

public void setDataNascimento(Calendar dataNascimento) {
    this.dataNascimento = dataNascimento;
}

public void setNomeCliente(String nomeCliente) {
    this.nomeCliente = nomeCliente;
}

@Coluna(posicao=0,nome="Código do Cliente")//posicao no jable e o nome para exibir na coluna
public Integer getCodigoCliente() {
    return codigoCliente;
}

@Coluna(posicao=3,nome="CPF")//posicao no jable e o nome para exibir na coluna
public String getCpf() {
    return cpf;
}

@Coluna(posicao=2,nome="Data de Nascimento", formato="%1$Td/%1$Tm/%1$TY") //posicao no jable, o nome para exibir na coluna e formato //para data, senão ele iria chamar toString de Calendar.
public Calendar getDataNascimento() {
    return dataNascimento;
}

@Coluna(posicao=1,nome="Nome do Cliente")
public String getNomeCliente() {
    return nomeCliente;
}

}[/code]

3º passo e o mais importante: implementar TableModelPadraoParaBean


import java.lang.reflect.Method;
import java.util.List;
import javax.swing.table.AbstractTableModel;

public class TableModelPadraoParaBean extends AbstractTableModel {
  private Class<?> classe;
  private List<?> lista;

   public TableModelPadraoParaBean(List<?> linhas) {
      this.setLinhas(linhas);
      if (linhas != null)
        this.classe = linhas.get(0).getClass();
   }

   public int getRowCount() {
      if (lista != null) {
         return lista.size();
      } else {
         return 0;
      }
   }

   public int getColumnCount() {
       int colunas = 0;
       for(Method m : classe.getDeclaredMethods()){
           if(m.isAnnotationPresent(Coluna.class)){
               colunas++;
           }
       }
      return colunas;
   }

   public boolean isCellEditable(int row, int col) {
      return false;
    }

    public Class getColumnClass(int c) {
      return getValueAt(0, c).getClass();
    }

    public void setLinhas(List<?> linhas) {
      this.lista = linhas;
      fireTableDataChanged();
   }

   public Object getValueAt(int rowIndex, int columnIndex) {
       try{
           Object objeto = lista.get(rowIndex);
           for(Method m : classe.getDeclaredMethods()){
               Coluna c = m.getAnnotation(Coluna.class);
               if(c != null && c.posicao() == columnIndex){
                   return String.format(c.formato(), m.invoke(objeto));
               }
           }
       }catch(Exception ex){
           ex.printStackTrace();
       }
       return "";
   }
    public String getColumnName(int coluna){
        for(Method m : classe.getDeclaredMethods()){
            Coluna c = m.getAnnotation(Coluna.class);
            if(c != null && c.posicao() == coluna ){
                return c.nome();
            }
        }
        return "";
    }
}

E para testar um exemplo usando o NetBeans:


import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import resultadoonline.gui.ClienteBean;
import resultadoonline.gui.TableModelPadraoParaBean;

public class NewJFrame extends javax.swing.JFrame {


    public NewJFrame() {
        initComponents();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jTable1.setModel(new TableModelPadraoParaBean(linhasClientes));
        jScrollPane1.setViewportView(jTable1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(28, 28, 28)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(34, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 303, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(139, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                linhasClientes = new ArrayList<ClienteBean>();
                ClienteBean cb1 = new ClienteBean();
                cb1.setCodigoCliente(1);
                cb1.setNomeCliente("Ronaldo");
                cb1.setDataNascimento(Calendar.getInstance());
                cb1.setCpf("131.216.564-89");

                ClienteBean cb2 = new ClienteBean();
                cb2.setCodigoCliente(2);
                cb2.setNomeCliente("Fernanda da Silva");
                cb2.setDataNascimento(Calendar.getInstance());
                cb2.setCpf("291.996.533-00");

                linhasClientes.add(cb1);
                linhasClientes.add(cb2);
                new NewJFrame().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    // End of variables declaration
    private static List<ClienteBean> linhasClientes;
}

Se ficar com dúvida no codigo me avisa…

Abraços

Entedi a logica do seu codigo, Vou dar uma olhadinha no Reflection pois eu confesso que não conheço.
So não entedi esse codigo abaixo:

private Class<?> classe;
(Method m : classe.getDeclaredMethods())
Alguem poderia me explicar o que é o Method e o classe.getDeclaredMethods()?

classe é a Classe do seu objeto que pode ser conseguido com objeto.getClass() ou NomeDaClasse.class.

Method é um método da classe. e Class.getDeclaredMethods retorna todos declarados nessa classe.

Entendi amigo! Andei lendo sobre o Reflection aqui o negocio é muito legal. com ele eu posso criar meus proprios annotations. Creio que a unica maneira de eu fazer uma unica tela so de consulta pra o meu sistema todo é mapear o bean. Desta forma pelo que eu pude entender no seu codigo so vou precisar prassar como modelo pra minha JTable a classe TableModelPadraoParaBean(List<?> linhas) certo?

Bom, eu não sabia que vc queria fazer isso em uma unica tela.Neste caso é melhor vc colocar + um metodo na classe TableModelPadraoParaBean para vc não ficar fazendo varias instancias na mesma tela.E ai vc atualiza o seu list… e em consequencia disso o jtabel ja vai ser avisado que houve mudança na lista.Segue o codigo:

public void atualiza(List<?> lista) {
        setLinhas(lista);
        
        if((lista != null))
        	this.classe = lista.get(0).getClass();
}

Lintz_net atraves do teu codigo eu montei um exemplo aqui com banco de dados e tudo mais quando eu consulto em uma tabela tudo certo, quando necessito mostrar na minha consulta um campo que faz Join com outra tabela não funciona! Eu estou usando JPA então quando populo meu bean na chave estrangeira eu tenho outro objeto. Vc já passou por isso?

Ixi… não tive este problema,não!!Como está criado o seu modelo?.
Como não tenho certeza como está seu modelo vou imaginar alguma situação como vc descreveu…

Mas te respondendo de imediato(e uma solução não muito elegante que tive agora) é vc criar um objeto que representa os dados do seu jtabel que junta todas as propriedades que vc precisa aprensentrar, dos dois objetos…

Me mostra um exemplo do seu código depois.

Abraços.

Olha o exemplo que fiz foi so pra testar se eu conseguia listar os dados na tabela mesmo quando eu tivesse um Join
Segue o exemplinho junto com o script do banco (mysql). Quanto ao modelo da classe eu usei o seu modelo a classe
TableModelPadraoParaBean. Esse exemplo foi feito no netbeans e utiliza JPA com Hibernate. Os dados foram inseridos manualmente nas tabelas do banco pra ser feita a consulta.

Olá josimarsis,

Como eu te falei antes, vc pode resolver criando um objeto que representa os dados do seu jtabel que junta todas as propriedades que vc precisa aprensentrar, dos dois objetos(clientes e empresa), ou vc pode criar um metodo no bean cliente que contém a informação da empresa que vc quer apresentar, p/exemplo:

  @Coluna(posicao=4,nome="Empresa")//posicao no jable e o nome para exibir na coluna
    public Integer getEmprCodigo() {
        return emprCodigo.getEmprCodigo();
    }

Abraços.

Veja se isso lhe ajuda… E um exemplo utilizand ouma biblioteca de desenvolvimento pra J2SE…
http://grupodax.wordpress.com/2009/05/03/exemplo-de-jtable-com-daxcomponents/

http://grupodax.blogspot.com/2009/05/daxcomponents-jtable.html

Espero que ajude…

Olá 71C4700 eu dei uma olhada no daxcomponents e achei legal e vou estuda-ló melhor. mas eu ja estou bem
adiantado na construção desta tabela graças a ajuda de vcs aqui do Guj. Estou utilizando Reflection

Atualmente eu tenho o seguinte problema:
Eu criei um RowSorter onde o usuario pode classificar os dados de maneira Crescente e Decrescente. A Classificação não funciona
para numeros e ou valores R$, Creio eu que seja pq a JTable interpreta todos os dados que eu passei pra ela como se fossem String.
Como modelo para a JTable estou utilizando este modelo que encontrei na net. Ele Recebe um List de Beans com Reflection e consegue interpreta-los

package comum;

import java.lang.reflect.Method;
import java.util.List;
import javax.swing.table.AbstractTableModel;

public class TableModelPadraoParaBean extends AbstractTableModel {
  private Class<?> classe;
  private List<?> lista;

    public TableModelPadraoParaBean(List<?> linhas) {
      this.setLinhas(linhas);
      if (linhas != null)
        this.classe = linhas.get(0).getClass();
   }

   public void atualiza(List<?> lista) {
        setLinhas(lista);

        if((lista != null))
        	this.classe = lista.get(0).getClass();
}


   public int getRowCount() {
      if (lista != null) {
         return lista.size();
      } else {
         return 0;
      }
   }

   public int getColumnCount() {
       int colunas = 0;
       for(Method m : classe.getDeclaredMethods()){
           if(m.isAnnotationPresent(Coluna.class)){
               colunas++;
           }
       }
      return colunas;
   }

    @Override
   public boolean isCellEditable(int row, int col) {
      return false;
    }

    @Override
    public Class getColumnClass(int c) {
      return getValueAt(0, c).getClass();
    }

    public void setLinhas(List<?> linhas) {
      this.lista = linhas;
      fireTableDataChanged();
   }

   public Object getValueAt(int rowIndex, int columnIndex) {
       try{
           Object objeto = lista.get(rowIndex);
           for(Method m : classe.getDeclaredMethods()){
               Coluna c = m.getAnnotation(Coluna.class);
               if(c != null && c.posicao() == columnIndex){
                   return String.format(c.formato(), m.invoke(objeto));
               }
           }
       }catch(Exception ex){
           ex.printStackTrace();
       }
       return "";
   }
    @Override
    public String getColumnName(int coluna){
        for(Method m : classe.getDeclaredMethods()){
            Coluna c = m.getAnnotation(Coluna.class);
            if(c != null && c.posicao() == coluna ){
                return c.nome();
            }
        }
        return "";
    }
}

Como neste caso posso dizer à minha JTable que determinada coluna vai ser Integer ou Float?
Galera assim que eu acertar esses probleminhas e terminar esse exemplo que estou montando vou postar aqui no
forum devidamente comentado e explicado para ajudar amigos que lidam com esse problema.

Via Reflection também é possivel saber que tipo sera retornado.

public Object returnType(int col){
 for(Method m : classe.getDeclaredMethods()){  
             Coluna c = m.getAnnotation(Coluna.class);  
             if(c != null && c.posicao() == coluna ){  
                 return m.getReturnType();
             }  
         }  
return null;
}

Coloca isso aqui no seu TableModel para vê se resolve…

    public Class getColumnClass(int c) {
      return getValueAt(0, c).getClass();
    }

Corrigam-me caso esteja errado, mais neste caso pra determinar se sua coluna vai ser Integer ou Float é no metodo

public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); }

No seu caso lá no método

public Object getValueAt(int rowIndex, int columnIndex) { try{ Object objeto = lista.get(rowIndex); for(Method m : classe.getDeclaredMethods()){ Coluna c = m.getAnnotation(Coluna.class); if(c != null && c.posicao() == columnIndex){ return String.format(c.formato(), m.invoke(objeto)); // Aqui vc ta declarando que todos os tipos serão transformados em String } } }catch(Exception ex){ ex.printStackTrace(); } return ""; }

Veja se é este caso, de vc está transformando todos os tipos em String.
Voce poderia retorna o c.formato().getClass, ou não? Pois o que importa pra vc não é o tipo? Poderia fazê-lo em outro metodo talvez…