Instanciando e populando uma JTable

Senhores,

Depois de muitas pesquisas no fórum e na Internet, resolver criar esse topico.

Estou criando uma pequena aplicação Swing no NetBeans que carrega uma JTable com dados de uma tabela do BD. Minha primeira dúvida é a seguinte:

1 - Criei os componentes visuais todos pelo NetBeans. A IDE gera um bando de códigos que nao podemos mexer. Eu coloquei uma JTable no meu JFrame, mas tenho dúvidas sobre como instanciar e usar esse objeto. Aparentemente, ele apenas declara uma referencia de instancia, mas não instancia. Porem, o objeto “físico” ja está no JFrame. Preciso instanciar isso na mão? " JTable jTable1 = new JTable();" ? Se sim, faço isso no construtor do JFrame?

2 - A tela ja está toda montadinha. Porem, quando estudei um pouco sobre Swing, eu lembro de ter visto que é necessário colocarmos containers e adicionarmos os componentes dentro desses containers e tal. Preciso fazer isso com a tabela? algo do tipo jFrame1.add(jTable1)? Lembrando que a tela já está toda montadinha visualmente.

3 - Não estou conseguindo popular essa JTable. Não sei se é por causa dos problemas acima ou se nao estou conseguindo realmente trazer os dados do banco. Tenho uma LIST com todos os dados da tabela. Queria apenas jogar essa LIST pra dentro da JTable. Existe alguma forma de jogar um ResultSet? acho que seria mais fácil.

Desde já, grato.

Sds,

Vinicius

Olá amigo;
Boa Tarde!

Me surpreendeu ninguem ter respondido até o momento. Vou dar um exemplo abaixo, talvez haja métodos mais fáceis, mas se persistir há de conseguir. Aqui funciona redondinho.

Coloque a jTable na mão mesmo pelo NB.
Crie uma classe que extenda DefaultTableModel e atribua na sua jTable da seguinte forma:

Note que estou levando os dados do DB num ArrayList

        ...
        ModelTableRDV model = null;
       
        model = new ModelTableRDV(al); // aqui passo o arraylista para a classe que extenda a DefaultTableModel
        jTableRDV.setModel(model);
        jTableRDV.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    }

Abaixo postarei a classe ModelTableRDV descrita acima:

package util;   
  
import javax.swing.table.DefaultTableModel;
import bean.RDV;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
  
public class ModelTableRDV extends DefaultTableModel {   
   private ArrayList dados = null;   

   public ModelTableRDV(ArrayList dados) {   
      this.dados = dados;
   }   
      
   @Override
   public int getColumnCount() {   
      return 6; //quantidade de campos do que terá na tabela
   }   
  
    @Override
   public int getRowCount() {   
      if (this.dados == null) {   
         return 0;   
      } else {   
         return this.dados.size();      
      }   
   }   
  
    @Override
   public Object getValueAt(int row, int column) {   
      RDV rdv = (RDV) this.dados.get(row);   // RDV é o meu objeto bean com seus gets e sets
         
      Object retorno = null;   
      if (column == 0) {   //pega os valores do objeto para retornar para a jTable
         retorno = rdv.getDespVeicNum();   
      } else if (column == 1) {
         retorno = rdv.getDespVeicData();
      } else if (column == 2) {   
         retorno = rdv.getDespVeicOrigem();   
      } else if (column == 3) {   
         retorno = rdv.getDespVeicDestino();   
      } else if (column == 4) {   
         retorno = rdv.getDespVeicKmTot();   
      } else if (column == 5) {   
         retorno = rdv.getDespVeicVlrTotal();   
      } 
      
      return retorno;   
         
   }   
  
    @Override
   public String getColumnName(int column) {   
      String columnName = "";   //rotulo de cabeçalho das colunas do jTable
      if (column == 0) {   
         columnName = "ID:";   
      } else if (column == 1) {   
         columnName = "Data:";   
      } else if (column == 2) {   
         columnName = "Origem:";   
      } else if (column == 3) {   
         columnName = "Destino:";   
      } else if (column == 4) {   
         columnName = "KM Total:";   
      } else if (column == 5) {   
         columnName = "Valor Total:";   
      }  
      return columnName;   
   }
}  

Deve funcionar, testa aí e retorne se precisar. Caso haja algum amigo que saiba uma maneira mais fácil de fazer, poste por favor.

Abraço à todos

Marco Aurélio

Só uma coisa: Não faça models extendendo DefaultTableModel, mas sim o AbstractTableModel.

Fernando

BINGO, AMIGOS!

Exatamente isso… Funcionou!!
Então para cada JTabel preciso criar um Model especifico??
Muito Obrigado!!

Olá Vinny, isto mesmo! Para cada jTable um model.

Fernando… qual a diferença entre DefaultTableModel e AbstractTableModel?

Os métodos são diferentes? Poderia postar um exemplo?

Abraço!

Marco A.

A diferença é que o DefaultTableModel é uma classe concreta, subclasse de AbstractTableModel, que é instanciada e setada automaticamente em uma JTable, caso tu não substitua ele definindo um novo setModel. Portanto, uma classe que já existem muitos métodos para manipulação de dados, nesse caso do tipo arrays e vector. A idéia de um novo TableModel é modificar essa manipulação de dados. Portanto uma classe que já tem todos os métodos necessários para esse fim e uso definido: Definição e manipulação dos dados através de um vector de dados. Extendendo uma DefaultTableModel, e não uma AbstractTableModel, sua classe vai ficar inchada com métodos que nunca serão utilizadas, já que a idéia é justamente modificar o jeito de manipulação de dados. Para isso, extendendo AbstractTableModel, você herda apenas os métodos realmente necessários, e aí sim, implementa os novos métodos para manipulação de dados, sem repetição.

Não sei se fui claro… :lol:

Fernando

Na verdade, escrevi tudo isso mas que pode se resumir em apenas uma palavra: Coesão.

Fernando

Fala Pessoal…
Problema Nº 1 resolvido!

Estou com um segundo problema agora… To implementando o método de exclusão, onde desejo fazer o seguinte: Quando o usuario clica em um registro da JTable, gostaria que um objeto fosse retornado. Este objeto eu mandaria como parametro para meu DAO de exclusão.
Mas percebi que os métodos que tenho disponíveis não fazem isso. Para pegar um valor, eu preciso dar um getValueAt(int row, int column) mandando o numero da linha e da coluna. Mas eu não sei em tempo de execução qual será a coluna que o usuario irá clicar. Eu preciso de um método que pegue a linha inteira e monte um objeto com esses valores. Esse método exsite?

Desde já agradeço,

Sds,

Vinicius

Faz o seguinte:

coloca a chave do registro que quer excluir na Jtable (primeira coluna por exemplo).

Depois vc faz:

int index = jTable1.getSelectedRow();
int chave = (Integer) jTable1.getValueAt(index, 0);

Qualquer linha que ele clicar será retornado o valor da chave (primeira coluna)

Sacou?

Abraço

Marco A.

Tentei criar uma tabela seguindo o modelo que o fanama mandou, mas na hora que rodo, onde deveria aparecer a tabela, fica tudo em branco.

Onde eu errei???

Só alterei o objeto que deve popular a tabela:

package br.com.progold.util;

import javax.swing.table.AbstractTableModel;
import br.com.progold.bean.NotaFiscal;
import java.util.ArrayList;  

public class ModelTabelaDados extends AbstractTableModel {     
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private ArrayList<NotaFiscal> dados = null;     

	public ModelTabelaDados(ArrayList<NotaFiscal> dados) {     
		this.dados = dados;  
	}     

	@Override  
	public int getColumnCount() {     
		return 6; //quantidade de campos do que terá na tabela  
	}     

	@Override  
	public int getRowCount() {     
		if (this.dados == null) {     
			return 0;     
		} else {     
			return this.dados.size();        
		}     
	}     

	@Override  
	public Object getValueAt(int row, int column) {     
		NotaFiscal notaFiscal = (NotaFiscal) this.dados.get(row);   // RDV é o meu objeto bean com seus gets e sets  

		Object retorno = null;     
		if (column == 0) {   //pega os valores do objeto para retornar para a jTable  
			retorno = notaFiscal.getNumero();     
		} else if (column == 1) {  
			retorno = notaFiscal.getEmpresa();  
		} else if (column == 2) {     
			retorno = notaFiscal.getCliente();     
		} else if (column == 3) {     
			retorno = notaFiscal.getValor();     
		} else if (column == 4) {     
			retorno = notaFiscal.getData();     
		} else if (column == 5) {     
			retorno = notaFiscal.getSituacaoDecodificada();     
		}   

		return retorno;     

	}     

	@Override  
	public String getColumnName(int column) {     
		String columnName = "";   //rotulo de cabeçalho das colunas do jTable  
		if (column == 0) {     
			columnName = "NUMERO";     
		} else if (column == 1) {     
			columnName = "EMPRESA";     
		} else if (column == 2) {     
			columnName = "CLIENTE";     
		} else if (column == 3) {     
			columnName = "VALOR";     
		} else if (column == 4) {     
			columnName = "DATA";     
		} else if (column == 5) {     
			columnName = "SITUACAO";     
		}    
		return columnName;     
	}  
}

E aqui a chamada dessa tabela:

package br.com.progold.core;

import java.awt.*;
import java.util.ArrayList;

import javax.swing.*;

import br.com.progold.bean.NotaFiscal;
import br.com.progold.dao.NotaFiscalDAO;
import br.com.progold.util.ModelTabelaDados;
import br.com.progold.util.Util;

public class AbaNFe extends JPanel {
	
	private JLabel labelPeriodo;
	private JTable tabelaNotas;
	private ModelTabelaDados modeloTabela;
	
	private static final long serialVersionUID = 1L;
	
	public AbaNFe(){
		super(new GridLayout(2, 1));
		adicionarComponentes();
	}

	private void adicionarComponentes() {
		
		try {
			
			String hoje = Util.getDate(0, "dd/MM/yyyy");
			labelPeriodo = new JLabel("Notas de "+hoje);
			//labelPeriodo.setSize(new Dimension(1024,20));
			this.add(labelPeriodo);
			NotaFiscalDAO nfDAO = new NotaFiscalDAO();
			ArrayList<NotaFiscal> dados = (ArrayList<NotaFiscal>) nfDAO.findAll(hoje);
			
			modeloTabela = new ModelTabelaDados(dados);
			tabelaNotas = new JTable(modeloTabela);
			tabelaNotas.setAutoscrolls(true);
			this.add(tabelaNotas);
			
		} catch (Exception e){
			e.printStackTrace();
		}
		
		
	}

}

Tem certeza que seu DAO está retornando alguma coisa?

Vlw ViniGodoy. Meu DAO não estava retornando nada.

Aproveitando o tópico. A linha com os nomes das colunas não aparece, como resolvo isso.

E tb, como faço pra adicionar uma barra de rolagem nos dados da tabela? Tentei usar o setAutoScrolls, mas não funcionou.

Você deve colocar a tabela em cima de um JScrollPane. Isso vai resolver os dois problemas:

[code]package br.com.progold.core;

import java.awt.*;
import java.util.ArrayList;

import javax.swing.*;

import br.com.progold.bean.NotaFiscal;
import br.com.progold.dao.NotaFiscalDAO;
import br.com.progold.util.ModelTabelaDados;
import br.com.progold.util.Util;

public class AbaNFe extends JPanel {

private JLabel labelPeriodo;
private JTable tabelaNotas;
private ModelTabelaDados modeloTabela;

private static final long serialVersionUID = 1L;

public AbaNFe(){
	super(new GridLayout(2, 1));
	adicionarComponentes();
}

private void adicionarComponentes() {		
	try {			
		String hoje = Util.getDate(0, "dd/MM/yyyy");
		labelPeriodo = new JLabel("Notas de "+hoje);
		this.add(labelPeriodo);
		NotaFiscalDAO nfDAO = new NotaFiscalDAO();
		ArrayList&lt;NotaFiscal&gt; dados = (ArrayList&lt;NotaFiscal&gt;) nfDAO.findAll(hoje);
		
		modeloTabela = new ModelTabelaDados(dados);
		tabelaNotas = new JTable(modeloTabela);
		this.add(new JScrollPane(tabelaNotas)); //Aqui			
	} catch (Exception e){
		e.printStackTrace();
	}
}

}
[/code]

Perfeito. Funcionou tudo direitinho agora.

Mto obrigado.

Tem como adicionar um campo de checkbox na tabela?

Para poder selecionar as linhas que o usuário quiser.

É só fazer o método getColumnClass() retornar Boolean.class para a coluna que tiver o tipo boolean.

Eu não tenho nenhum método getColumnClass().

Tenho que sobreescrever como foi feito com o getColumnName(int column)?

Isso mesmo.

Alterei o modelo da minha tabela, colocando o método getColumnClass() e mudando o getValueAt() para setar na primeira coluna um JCheckBox (que foi inserido no bean do objeto). Dessa forma deu erro, pois não foi possível dar o cast em um objeto JCheckBox para um Boolean.

Alterei o retorno da primeira coluna do metodo getColumnClass() para JCheckBox.class. Dessa forma não tem erro, mas ao invés de aparecer um checkbox, aparece apenas o nome do objeto.

O que eu gostaria de fazer é colocar os checkbox, para que possa validar/assinar/enviar várias notas fiscais de uma só vez. Qual a melhor forma para isso?

public class ModelTabelaDados extends AbstractTableModel {     
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private ArrayList<NotaFiscal> dados = null;     

	public ModelTabelaDados(ArrayList<NotaFiscal> dados) {     
		this.dados = dados;  
	}     

	@Override  
	public int getColumnCount() {     
		return 7; //quantidade de campos do que terá na tabela  
	}     

	@Override  
	public int getRowCount() {     
		if (this.dados == null) {     
			return 0;     
		} else {     
			return this.dados.size();        
		}     
	}     

	@Override  
	public Object getValueAt(int row, int column) {     
		NotaFiscal notaFiscal = (NotaFiscal) this.dados.get(row);   // RDV é o meu objeto bean com seus gets e sets  

		Object retorno = null;     
		if (column == 0) {   //pega os valores do objeto para retornar para a jTable
			retorno = notaFiscal.getCheckBox();
		} else if (column == 1) {
			retorno = notaFiscal.getNumero();     
		} else if (column == 2) {  
			retorno = notaFiscal.getEmpresa();  
		} else if (column == 3) {     
			retorno = notaFiscal.getCliente();     
		} else if (column == 4) {     
			retorno = notaFiscal.getValor();     
		} else if (column == 5) {     
			retorno = notaFiscal.getData();     
		} else if (column == 6) {     
			retorno = notaFiscal.getSituacaoDecodificada();     
		}   

		return retorno;     

	}     

	@Override  
	public String getColumnName(int column) {     
		String columnName = "";   //rotulo de cabeçalho das colunas do jTable  
		if (column == 0) {
			columnName = "";
		} else if (column == 1) {
			columnName = "NUMERO";     
		} else if (column == 2) {     
			columnName = "EMPRESA";     
		} else if (column == 3) {     
			columnName = "CLIENTE";     
		} else if (column == 4) {     
			columnName = "VALOR";     
		} else if (column == 5) {     
			columnName = "DATA";     
		} else if (column == 6) {     
			columnName = "SITUACAO";     
		}    
		return columnName;     
	}
	
	@Override
	public Class getColumnClass(int column){
		if (column == 0) {
			return Boolean.class;
		} else if (column == 1) {
			return String.class;     
		} else if (column == 2) {     
			return String.class;     
		} else if (column == 3) {     
			return String.class;     
		} else if (column == 4) {     
			return String.class;     
		} else if (column == 5) {     
			return String.class;     
		} else if (column == 6) {     
			return String.class;     
		} else {
			return String.class;
		}
	}
}

E alterei a minha

Você não deve retornar um checkbox no getValueAt. Basta retornar o valor boolean que está definido na coluna (true ou false). O JTable se encarrega de renderizar esse boolean como um checkbox.