Mais uma vez JTable

32 respostas
G

Buenas pessoal, mais uma vez venho pedir um auxilio com JTables, comecei a fazer o model, mas verifiquei um problema que parece ser bem complicado, vamos lá.

Tenho uma classe Pessoa e duas que extendem ela (PessoaFisica, PessoaJuridica), e como na maioria dos casos de hernaça temos atributos nas classes filho que não encontramos na pai, mas ao começar o model pensei em fazer um List<Pessoa> para armazenar os dados, mas me deparei com o problema de ter que enviar informações das classes filho, alguém tem alguma sugestão de como implementar isso??

Vlw gurizada

PS.:
Código da classe

package Model;

import java.util.List;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author Guilherme Santos Souza
 */
public class ContatosTableModel extends AbstractTableModel {

    private static final String[] COLUNAS = {"Nome","Endereço","Data","Telefones","CPF/CNPJ"};
    private List&lt;Pessoa&gt; dados;

    public ContatosTableModel(){
        
    }

    public int getRowCount() {
        return dados.size();
    }

    public int getColumnCount() {
        return COLUNAS.length;
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        Pessoa p = dados.get(rowIndex);
        switch(columnIndex){
            case 1: return p.getNome();
            case 2: return p.getEndereco();
            case 3: if(p instanceof PessoaFisica){
                        
                    }
            case 4: return p.getTelefones();
        }
        return null;
    }

    @Override
    public Class&lt;?&gt; getColumnClass(int columnIndex){
        return String.class;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex){
        return false;
    }

}

32 Respostas

V

Normalmente, basta fazer com que seus TableModels também reflitam a hierarquia das suas classes.

Isso é, vc cria seu PessoaTableModel abstract e faz um filho PessoaFisicaTableModel, só complementando o que faltou.

G

Mas eu quero usar apenas uma uma GUI com JTable, então, neste caso eu não teria que dividir os dados em duas GUI’s, uma para Pessoa Fisica e outra para Pessoa Juridica??

V

Não entendi. Você quer ter a mesma tela para tratar dados diferentes?

Se for só para exibir, simplesmente passe o model inteiro como parâmetro para essa tela.

G

Eu pensei assim, uma mesma tabela com os dois tipos de pessoa e para alteração de dados e talvez uma coluna dizendo qual é o tipo de pessoa, um botão “Editar” que abriria outra GUI onde eu editaria os dados, haveria também um campo de filtro dos resultados, caso eu queira mostrar apenas um tipo ou mesmo por uma String, mas isso não vem ao caso.

V

Mas se são dados diferentes, daos diferentes, e campos diferentes, fica um pouco difícil fazer o que você quer com uma tela genérica. Exigiria você criar uma espécie de model para sua tela inteira.

G

Na realidade os dados são os mesmos, mas com nomes diferentes, por isso eu dividi em duas classes filho, e na GUI eu teria por exemplo para os campos datadefundação(Juridica) e datadenascimento(Fisica) seria apenas “Data” na GUI, entende.

D

Olha, não entendi direito o problema. Quando você tem um tipo de classe A e estende outras AB, AC, AD, todas podem ser instanciadas a partir do próprio A

A a = new AD();

Assim sendo, qual o problema em ter um ArrayList para armazenar os dados dos filhos PessoaFisica e PessoaJuridica?
Uma vez os dados dentro da ArrayList, é possível preencher a JTable.

Assim sendo, o ArrayList suporta tranquilamente os objetos das duas pessoas.
A questão é se todas as colunas terão valores compatíveis entre ambas as classes filho.

M

Deve ser um trabalho dificil pra caramba esse.

V

hahahaha, resquícios do outro tópico.

G

Gente remodelei o sisteminha, agora estou com o seguinte table model, mas não consigo designá-lo como TableModel da JTable, segue o código do Model:

public class PessoasTableModel extends AbstractTableModel {

    public static final String[] COLUNAS = {"Nome","Endereço","CPF/CNPJ","Data","E-mail","Telefones"};
    private List&lt;Pessoa&gt; pessoas;

    public PessoasTableModel(List&lt;Pessoa&gt; pessoas, String[] COLUNAS) {
        this.pessoas = pessoas;
    }
    public int getRowCount() {
        return pessoas.size();
    }
    public int getColumnCount() {
        return COLUNAS.length;
    }
    public Object getValueAt(int rowIndex, int columnIndex) {
        Pessoa p = pessoas.get(rowIndex);
        switch(columnIndex){
            case 1: return p.getNome();
            case 2: return p.getEndereco();
            case 3: return p.getDocumento();
            case 4: return p.getData();
            case 5: return p.getEmail();
            case 6: return p.getTelefones();
            default: return "ERRO OPÇÃO NÃO ENCONTRADA";
        }
    }
    @Override
    public Class&lt;?&gt; getColumnClass(int columnIndex){
        return String.class;
    } 
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex){
        return false;
    }
}

Pode estar faltando alguma parte no código, sei la, valeu pela força pessoal.

V
  1. Tire o segundo parâmetro do construtor, ele não está servido para nada;
  2. Pq não consegue? Dá algum erro?
G

Bom eu estava passando o segundo parâmetro pois ele seria o array de String que conteria as colunas, certo?

G

Achei o erro ele ta estourando uma NPE pq a minha lista de pessoas está vazia, como eu devo fazer para que a tabela não entenda a lista vazia como nula, ou seja como eu posso ficar sem nenhuma pessoa na minha lista sem estourar o ter que tratar a NPE.

V

Passe uma lista vazia para o JTable, não null.

Se realmente precisar passar null, mude o método getRowCount:

public int getRowCount() { return pessoal == null ? 0 : pessoas.size(); }

G

Acho que não entendeu, segue o código e o stack da exceção:

TableModel:

public class PessoasTableModel extends AbstractTableModel {

    public static final String[] COLUNAS = {"Nome","Endereço","CPF/CNPJ","Data","E-mail","Telefones"};
    private List&lt;Pessoa&gt; pessoas;

    public PessoasTableModel(List&lt;Pessoa&gt; pessoas) {
        this.pessoas = pessoas;
    }

    public int getRowCount() {
        return pessoas.size();
    }

    public int getColumnCount() {
        return COLUNAS.length;
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        Pessoa p = pessoas.get(rowIndex);
        switch(columnIndex){
            case 1: return p.getNome();
            case 2: return p.getEndereco();
            case 3: return p.getDocumento();
            case 4: return p.getData();
            case 5: return p.getEmail();
            case 6: return p.getTelefones();
            default: return "ERRO OPÇÃO NÃO ENCONTRADA";
        }
    }

    @Override
    public Class&lt;?&gt; getColumnClass(int columnIndex){
        return String.class;
    } 

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex){
        return false;
    }
}

Metodo de set model da GUI:

public class VisualizarContatos extends javax.swing.JFrame {

    private GerenciaPessoas gerenciaPessoas;

    public VisualizarContatos() {
        initComponents();
        gerenciaPessoas = new GerenciaPessoas();
        tbPessoas.setModel(new PessoasTableModel(gerenciaPessoas.getListPessoas()));
//...

Stack:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at View.VisualizarContatos.initComponents(VisualizarContatos.java:57)
        at View.VisualizarContatos.&lt;init&gt;(VisualizarContatos.java:15)
        at View.Inicial$1.actionPerformed(Inicial.java:21)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2012)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2335)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:404)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:253)
        at java.awt.Component.processMouseEvent(Component.java:6108)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
        at java.awt.Component.processEvent(Component.java:5873)
        at java.awt.Container.processEvent(Container.java:2105)
        at java.awt.Component.dispatchEventImpl(Component.java:4469)
        at java.awt.Container.dispatchEventImpl(Container.java:2163)
        at java.awt.Component.dispatchEvent(Component.java:4295)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4461)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4125)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4055)
        at java.awt.Container.dispatchEventImpl(Container.java:2149)
        at java.awt.Window.dispatchEventImpl(Window.java:2478)
        at java.awt.Component.dispatchEvent(Component.java:4295)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:604)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
V

E cadê o trecho de código onde a exception está ocorrendo?
É na linha 57, dentro do método initComponents.

G

é que eu montei tudo no construtor aqui na msg para ficar melhor visualizavél, mas ta estourando na linha onde eu seto o novo Model:

tbPessoas.setModel(new PessoasTableModel(gerenciaPessoas.getListPessoas()));

Essa é a linha onde ta estourando

V

Não pode ser, o erro está dentro do método initComponents, não fora.

G

é que eu alterei o código do initComponents() :oops:

E antes que alguém diga que é impossivel mexer no intiComponents() é possivel é só ir na area de montagem da GUI e clicar na opção “personalizar código”.

V

Anexa seu o código todo dessa tela aqui, please.

Use a opção de attachments, que fica logo abaixo da caixa onde vc escreve o texto, e não a tag [code]

G

Segue os anexos, vlwzão pela força aí XD

V

Troque seu construtor para:

public VisualizarContatos() { gerenciaPessoas = new GerenciaPessoas(); initComponents(); }

Você precisa do gerenciaPessoas criado antes de chamar o initComponents.

G

puts que coisa de noob, sério, ateh fiquei envergonhado agora com esse erro bizarramente tosco!
Isso é o que da ficar muito tempo longe dos códigos, valeu mesmo, mais uma vez, Vinny!

J

guisantogui,

Faz um teste pra ver…Não tenho certeza que vai dar certo pois não testei aqui…

No seu método getValueAt coloque:

case 3: if(p.getClass() == PessoaFisica.class){
			        return ((PessoaFisica)p).getDatadenascimento();
		           }
V

Você ficou muito assustado com o TableModel, sendo que o erro estava em outro lugar.
Mas é sempre bom seguir a exception. Se ela diz que ocorre na linha 57 do initializeComponents, ocorre na linha 57 do initializeComponents, e não no TableModel.
Ele nem aparecia na sua exceção.

Foi só olhar o que tinha na linha e ver onde você estava inicializando as coisas que o erro apareceu.

G

vlw mesmo pela força, olha só tentei resolver aqui, mas to meio perdido com esse negócio de table model, tipo onde eu seto o meu array com o nome das colunas, pq agora ta aparecendo “A B C D E F G” como colunas.

V

Faltou sobrescrever o método getColumnName. Só depois dele a JTable vai saber que o nome do seu array é o que deve ser usado na sua JTable.

G

Era isso ai mesmo Vinny, mais uma vez valeu pelas milhares de dicas XD e Default Table Model NUNCA MAIS :smiley:

V

Sim.

Lembre-se que quando você tem um TableModel próprio, você não deve usar diretamente os métodos getValueAt e setValueAt. Deixe eles pro JTable. No seu caso, crie um método get, que já retorne um objeto de dentro do model, bonitinho.

Aí basta alterar esse objeto e chamar o método fireTableUpdated, na linha dele. :slight_smile:

Nunca mais você fará casts. :slight_smile:

E dê uma olhada no model do Mark. Faz montar tabelas ser parecer uma piada… e de bom gosto!

G

por hoje tenho uma última duvida.

Para mim implemtar um metodo de addRow no meu model eu devo chamar o fireTableRowsInserted? o mesmo para sitema para deletar e alterar? Caso sim, como eu iria chamar o metodo afinal a classe é abstrata e não posso instancia-lá.

Como eu procederia daí? :?

V

A classe é abstrata, mas os métodos fire não. É esse o serviço que o AbstractTableModel presta, e por isso é vantajoso usa-lo ao invés de implementar diretamente a interface TableModel. Eis um exemplo (esse método vai no seu model):

public void add(Pessoa p) { pessoas.add(p); fireTableRowsInserted(p.size()-1, p.size()-1); }

G

vlw pela dica de como implementar, por hoje vou dar uma pausa ai na programação, vou ver se amanha continuo. De qual quer forma brigadão mais uma vez pela força!

Criado 12 de novembro de 2010
Ultima resposta 7 de dez. de 2010
Respostas 32
Participantes 5