Alimentar um jTable com uma select

Faço uma select no meu banco e gostaria de alimentar um jTable com os resultados dessa select e não faço nem idéia de onde partir para isso.
Alguém já fez algo parecido?

P.S.: uso o NetBeans 5 e gerei a parte visual usando Swing pelo próprio editor do NetBeans.

Opa…
olha só, supondo que o seu problema não é com o select, mas realmente com a maneira de alimentar um JTable (a partir de uma List retornada do seu método de consulta), eu vou te mandar esse exemplo anexo.
Como disse, suponho que você saiba fazer a consulta e retornar uma List.

Qualquer coisa é só postar!

[]'s

Cara…do select direto acho complicado.
Já fiz isso uma vez e usei um ArrayList.
Faz o seu select e atribui ele a um ResultSet. Daí você cria um ArrayList e faz um get do ResultSet. Cria um loop while e vai adicionando os elementos nesse ArrayList. Como o JTable não aceita o ArrayList como parâmetro você vai ter que passar esse List pra array. Passa esse array como parâmetro na hora de definir o modelo da sua tabela.
Ficou complicado? Posto um exemplo daqui a pouco.

Vamos por partes. hehe.

  • O select eu faço normal, sem nenhum problema;
  • Eu consigo até fazer um laço while do resultset do tipo:
ResultSet rs = stm.executeQuery("select max(ECO_ID) eco_id from email_controle");
      while(rs.next()){
       rs2 = rs.getInt("eco_id");
      }

Agora o meu problema que ainda não consegui solucionar é jogar a informação do meu while em um jTable, lembrando que gerei a minha tela no NetBeans e o jTable não tenho controle total sobre o código, parte do código que é gerado automaticamento pelo NetBeans eu não consigo alterar.
Basicamente eu tenho um select retornando dados normal e tenho o jTable já criado normal também, mas como eu ir montando a grade de forma dinâmica conforme a minha consulta?
Se alguém tiver um exemplo simples pode mandar.

[quote=petter]Vamos por partes. hehe.

  • O select eu faço normal, sem nenhum problema;
  • Eu consigo até fazer um laço while do resultset do tipo:
ResultSet rs = stm.executeQuery("select max(ECO_ID) eco_id from email_controle");
      while(rs.next()){
       rs2 = rs.getInt("eco_id");
      }

lembrando que gerei a minha tela no NetBeans e o jTable não tenho controle total sobre o código, parte do código que é gerado automaticamento pelo NetBeans eu não consigo alterar.
.[/quote]

Consegue sim…copia o código pra outra IDE tipo o eclipse e seja feliz.

Opa…

Colega, vc consegue ter controle sobre a JTable sim, mesmo fazendo a GUI no NetBeans (eu uso o NetBeans aqui).

Vamos lá… com relação ao meu exemplo, esse eu fiz na mão mesmo, mas o mais importante lá são os métodos…

Vamos por partes: (vou usar um exemplo real aqui, de um programinha que fiz)

Primeiramente, eu te aconselho a criar um método que faça a consulta, e retorne para você um List com as informações:

exemplo:

public List<Evento> obterEventos() throws SQLException, Exception{        
        
        Evento umEvento = null;
        List<Evento> eventos = new ArrayList<Evento>();
        DAOLancamento daoLancamento = new DAOLancamento();
        
        try{             
            
           
            conn = factoryConexao.getConnection();
          
            String SQL = "SELECT * FROM evento ORDER BY data DESC" ;
            PreparedStatement stmt = conn.prepareStatement(SQL, 
                                                         ResultSet.TYPE_SCROLL_INSENSITIVE, 
                                                         ResultSet.CONCUR_READ_ONLY);
                       
            ResultSet resultSet = stmt.executeQuery();       

            while (resultSet.next()){

                umEvento = new Evento();

                umEvento.setId(resultSet.getInt("id"));
                umEvento.setDescricao(resultSet.getString("descricao"));  
                umEvento.setData(resultSet.getDate("data"));                
                
                // o evento já sai com todos os seus lançamentos
                umEvento.setLancamentos(daoLancamento.obterLancamentos(umEvento));
                
                eventos.add(umEvento);                        
                umEvento = null;
            }                

            stmt.close();
        }
        finally{   

            conn.close();
            return eventos;
        }
    }

Jóia?! Até aqui beleza, você só fez o suficiente para ter os dados em um List…
Agora, para ter um controle maior sobre seu JTable (mesmo que ele tenha diso criado com o NetBeans), você pode criar algumas classes que te auxiliam na personalização.

Vamos usar 3: uma que extenda DefaultTableCellRenderer, uma que extenda DefaultTableColumnModel, e uma que extenda AbstractTableModel.

a que extende DefaultTableCellRenderer

/*
 * CellRendererEvento.java
 *
 * Created on 22 de Março de 2006, 22:23
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */


import java.awt.Color;
import java.awt.Component;
import javax.swing.JLabel;
import javax.swing.table.DefaultTableCellRenderer;

/**
 *
 * @author Luiz Gustavo Stábile de Souza
 */
public class CellRendererEvento extends DefaultTableCellRenderer {
    

    public CellRendererEvento() {
        super();        
    }
    

    private Color getCellColor(){
        
        return Color.BLACK;
    }
    
    
    public Component getTableCellRendererComponent(javax.swing.JTable table,
            Object value, boolean isSelected, boolean hasFocus, int row, int column){
        
        JLabel label = (JLabel)super.getTableCellRendererComponent(
                table, value, isSelected, hasFocus, row, column);
        
        Color corFundoZebrado = new Color(240, 240, 240);

        label.setFont(new java.awt.Font("Arial", 0, 12));
        
        if((row % 2) == 0){
            label.setBackground(Color.WHITE);
        }
        else{
            label.setBackground(corFundoZebrado);
        }
        
        if(column == 0){
            label.setHorizontalAlignment(CENTER);
        }
        else if(column == 1){
            label.setHorizontalAlignment(LEFT);
        }
        else if(column == 2){
            label.setHorizontalAlignment(RIGHT);
        }
        
        return label;
    }
    
}

…lhe permite ter controle sobre a configuração de cada célula. Você pode colocar a cor da fonte de cada coluna de uma cor, fazer um grid zebrado (o que está sendo feito aqui), enfim, serve para configurar cada célula.

A que extende DefaultTableColumnModel

import java.awt.FontMetrics;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableColumn;

/**
 *
 * @author Luiz Gustavo Stábile de Souza
 */
public class ColumnModelEvento extends DefaultTableColumnModel{
    

    public ColumnModelEvento(FontMetrics fm) {
            
            int digito = fm.stringWidth("0");
            int letra = fm.stringWidth("M");
            addColumn(criaColuna(0, 10 * letra, fm, false, "Cadastro"));
            addColumn(criaColuna(1, 100 * letra, fm, true, "Descrição do Evento"));
            addColumn(criaColuna(2, 15 * digito, fm, false, "Valor Total"));
       
    }
    
    private TableColumn criaColuna(int columnIndex, int largura, FontMetrics fm, boolean resizable, String titulo){
        
        int larguraTitulo = fm.stringWidth(titulo + "  ");
        if (largura < larguraTitulo){
            largura = larguraTitulo;            
        }
        
        TableColumn col = new TableColumn(columnIndex);
        col.setCellRenderer(new CellRendererEvento());
        col.setHeaderRenderer(null);
        col.setHeaderValue(titulo);
        col.setPreferredWidth(largura);
        if(!resizable){
            
            col.setMaxWidth(largura);
            col.setMinWidth(largura);
        }
        col.setResizable(resizable);
        return col;        
    }    
}

…lhe permite configurar quais colunas existirão na JTable:

addColumn(criaColuna(0, 10 * letra, fm, false, "Cadastro"));
addColumn(criaColuna(1, 100 * letra, fm, true, "Descrição do Evento"));
addColumn(criaColuna(2, 15 * digito, fm, false, "Valor Total"));

Observe este trecho:

col.setCellRenderer(new CellRendererEvento());

aqui é indicado que o ColumnModel deve usar, para configurar cada célula, o CellRenderer que foi criado anteriormente. Se você não estiver usando um CellRenderer (o que deixaria a JTable com uma aparência padrão), basta deixar o parâmetro como null.

A que extende AbstractTableModel

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author Luiz Gustavo Stábile de Souza
 */
public class TableModelEventos extends AbstractTableModel{
    
    private List<Evento> eventos;
    private SimpleDateFormat simpleDateFormat;
    
    public TableModelEventos(List<Evento> eventos) {
        
        this.eventos = eventos;
        simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");
    }
    
    public Object getValueAt(int rowIndex, int columnIndex){
        
        Evento umEvento = eventos.get(rowIndex);
        
        switch(columnIndex){       
            case 0: return simpleDateFormat.format(umEvento.getData());
            case 1: return umEvento.getDescricao();
            case 2: return NumberFormat.getCurrencyInstance().format(umEvento.getValorTotal());
        }
        return null;       
    }
    
    public int getRowCount(){
        
        return eventos.size();
    }
    
    public int getColumnCount(){
        return 3;
    }
    
    public Evento getValues(int rowIndex){
        return eventos.get(rowIndex);
    }
    
}

… é a classe que manipula os dados, onde você pode definir a formatação de cada informação (não da célula) que vai aparecer na JTable, para cada coluna. É essa classe que vai receber o List criado por aquele método lá do início… :smiley:

Bom, tendo feito isso, agora nos resta ver como falar para a JTable usar todo esse troço.
Como eu disse, mesmo criando a JTable no NetBeans, você tem controle sobre ela no restante do código.

Para configurar sua JTable, toda vez que você atualizar os dados, crie na GUI um método como este:

public void setListaEventos(List<Evento> eventos){        
        
        this.eventos = eventos;
        
        tableEventos.setModel(new TableModelEventos(eventos));
        tableEventos.setSelectionModel(new DefaultListSelectionModel(){
            
             public String toString(){
                
                return "tableEventos";
            }
             
        });       
        
        tableEventos.getSelectionModel().addListSelectionListener(this);
        tableEventos.setAutoCreateColumnsFromModel(false);
        tableEventos.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        FontMetrics fm = tableEventos.getFontMetrics(tableEventos.getFont());
        tableEventos.setColumnModel(new ColumnModelEvento(fm));
        
        setListaEventosImpressao(gerarEventosImpressao(eventos));
        
        if (!eventos.isEmpty()){
            setEvento(eventos.get(0));   
        } 
        else{
            limparEvento();
        }
    }

E quando você chama esse método? Toda vez que precisar atualizar dua JTable. Basta passar para ele o List retornado por aquele método lá do início (e que muito provavelmente estará em uma classe DAO).

Vamos, novamente, por partes:

Aqui você informa que o modelo (que possui os dados) adotado por sua JTable (tableEventos) é um TableModelEventos, que recebe uma Lista com os dados a apresentar.

tableEventos.setModel(new TableModelEventos(eventos));

Aqui você diz que ele vai usar o seu modelo de colunas, e não o padrão:

tableEventos.setAutoCreateColumnsFromModel(false);

Aqui você diz que a JTable vai usar o seu ColumnModel personalizado:

tableEventos.setColumnModel(new ColumnModelEvento(fm));

Bom… dê uma digerida nisso tudo :D, e qualquer dúvida com relação ao código, poste aqui novamente, ou sinta-se à vontade para entrar em contato via e-mail, se preferir.
Se te serve de consolo, trabalhar com JTable, usando modelos, é complicado para a maioria dos programadores, e é complicado no início, mas é a melhor maneira de se ter controle total sobre a JTable. Com essa abordagem você pode, por exemplo, colocar um JComboBox em uma célula, ou um JCheckBox.

Quando comecei eu tomei como base um exemplo apresentado pelo Fernando Lozano, na Java Magazine ed. 25.

Dê uma olhada aqui também… vai te ajudar

bom… taí

boa sorte :thumbup:

Sobre o exemplo acima dá um erro que não consegue localizar a class Evento e DAOLancamento? O que são essas classes? Foram criadas por vc?

Se você tentar rodar vai dar erro mesmo, pois esses são apenas trechos de código, com o que realmente é interessante para explicar a sua dúvida. Eles são parte de um programa aqui.

Tente levar esses exemplos para o contexto da sua aplicação.

Qualquer coisa poste aí!

[]'s

Ah sim, mas a principio o que me travou foram os seguintes problemas:

  • O fazem as classes Evento e DAOLancamento?

Pessoal depois de muitos testes e da ajuda de vcs consegui fazer o seguinte tenho um array que é alimentado pela minha select e de outro lado tenho a minha jTable. Como enviar os dados para a jTable a partir da ação de um botão por exemplo. Fazendo um laço while? Um laço for?

Bom, respondendo às suas dúvidas quanto as classes Evento e DAO:

Essa classe Evento é uma classe qualquer, que poderia ser, por exemplo, uma classe Cliente. Ela é a classe cujos objetos eu preciso mostrar no JTable.
Já a classe DAOLancamento, é um tipo de classe que trata (pelo menos no meu caso) exclusivamente do acesso ao banco. Por exemplo: todos os métodos que realizam rotiunas de banco de dados, como inserção, edição, exclusão, consulta… enfim, todas as rotinas de banco, ficam em classes do tipo DAO.
Essa classe DAOLancamento em específico faz uma consulta no banco de dados me retorna todos os lançamentos de um Evento, e a classe DAOEvento por sua vez (que é onde está o método que você viu retornar um List, é a classe que me retorna os eventos que eu preciso apresentar no JTable.

Ajudou? :smiley:

qualquer coisa posta aí…

[]'s