Exemplo de TableModel

Tive que criar uma tela com JTable no curso que estou fazendo e implementei também um TableModel. Como procurei deixar o código comentado, achei interessante postar pro pessoal daqui.

O TableModel está bem simples e implementado para exibir dados de uma classe Socio. Estou anexando também uma classe JFrame que fiz só para teste mesmo.

Pra quem se interessar e achar algum erro ou quiser dar uma sugestão de melhoria, os comentários serão muito bem vindos.

Edit: O método getSocio estava com retorno void, o erro foi corrigido.

O sócio foi modificado, recebendo campos com data e valor numérico. Assim fica visível que a JTable formata automaticamente os dados dependendo do tipo.

Post com explicação passo a passo: http://devsv.wordpress.com/2012/07/08/como-implementar-um-tablemodel/.

Falou…

Ficou excelente!

Morte ao DefaultTableModel! \o/

Belo exemplo!

Morte ao DefaultTableModel! \o/

Valeu pelos comentários.

Praticamente tudo que sei sobre Table Model, eu devo a assinatura de vocês. :smiley:

E valeu Vini. Seus posts e exemplos sempre me ajudam muito.

Morte ao DefaultTableModel! \o/

morte ao tableModel ?!??!?!?!

desculpe a ignorância mais como eu faço minha própria table? (sou leigo ainda!!)

pra aparecer lah na form certinho se nao for arrastando jtable?

vlw

[quote=thayson]morte ao tableModel ?!??!?!?!

desculpe a ignorância mais como eu faço minha própria table? (sou leigo ainda!!)

pra aparecer lah na form certinho se nao for arrastando jtable?

vlw[/quote]

Morte ao DefaultTableModel, não o TableModel.

A JTable faz seu papel muito bem, o importante é saber como os dados vão aparecer na tabela.

Ola galera! estou seguinto a orientaçao de vcs em usar o TableModel ao invé do DefautTableModel.
porem to com um problema quando insiro o valor na tabela. ele da o seguinte erro:

[quote]Exception in thread “AWT-EventQueue-0” java.lang.NullPointerException
at javax.swing.JTable.prepareRenderer(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
at javax.swing.plaf.ComponentUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)[/quote]

tentei usar o exemplo do colega Eric Yuzo

a diferença do dele pro meu é q eu quero adicionar na tabela valores q estao nos campos de entrada. e no dele o valores ja estao inseridos. porem o meu ta apresentando esse erro, gostaria de saber se vcs sabem oq é.

Poste o trecho do código que está inserindo o valor no TableModel.

A propósito, o TableModel do exemplo não tem nenhum valor setado por padrão. A lista de sócios é populada na tela de teste.

[quote=Eric Yuzo]Poste o trecho do código que está inserindo o valor no TableModel.

A propósito, o TableModel do exemplo não tem nenhum valor setado por padrão. A lista de sócios é populada na tela de teste.[/quote]

entendi…

e tb consegui consertar oq eu precisava, era um erro bobo! agora ta funcionando de boa! fico muito agradecido ao Eric Yuzo, com sua dica consegui entender… e concluí q é muito melhor usar TableModel. valew galera obrigado… caso queiram ver oq eu tava fazendo é so falar!

Aeh galera… mais outra pergunta!

oq é melhor trabalhar com hashMap ou ArrayList ? Eu vi exemplos de codigos com hashMap porém nao entendi! e gostaria de saber a opniao de vcs!!

Para o TableModel, use uma lista mesmo.

Na lista você guarda os objetos que representam as linhas e que podem ser acessados pelo índice. Lembre-se que a JTable, na hora de renderizar as células, busca o valor pelo índice e não por uma chave.

Ótima implementação, ficou incrível.

:smiley:

Então galera, já fazem muitos anos que venho acompanhando o GUJ, acho que desde 2003 quando entrei na faculdade.
Na área de programação já é quase 10 anos, tenho muita intimidade com java swing, e acho que posso dar um parecer técnico ao meu ponto de vista.

O DefaultTabelModel não pode, nem deve ser morto, ele é o feijão com arroz, o básico onde as pessoas usam sem entender para fazer funcionar o básico de uma tabela.

Quando a pessoa passa por uma situação diferente tipo colocar imagem, jProgressBar dentro da tabela, a pessoa estuda o caso mais a fundo.
Ai sim passa a entender o funcionamento de um model e vai implementar um com esses exemplos todos que estão rolando por aqui no forum.

É ótimo os exemplos, eu os uso, mas para quem esta no javaBaby, tem que começar de algo básico e ir progredindo.

Abraços!

[quote=SneepS]Então galera, já fazem muitos anos que venho acompanhando o GUJ, acho que desde 2003 quando entrei na faculdade.
Na área de programação já é quase 10 anos, tenho muita intimidade com java swing, e acho que posso dar um parecer técnico ao meu ponto de vista.

O DefaultTabelModel não pode, nem deve ser morto, ele é o feijão com arroz, o básico onde as pessoas usam sem entender para fazer funcionar o básico de uma tabela.

Quando a pessoa passa por uma situação diferente tipo colocar imagem, jProgressBar dentro da tabela, a pessoa estuda o caso mais a fundo.
Ai sim passa a entender o funcionamento de um model e vai implementar um com esses exemplos todos que estão rolando por aqui no forum.

É ótimo os exemplos, eu os uso, mas para quem esta no javaBaby, tem que começar de algo básico e ir progredindo.

Abraços![/quote]

E quem paga o custo da manutenção das tabelas deixadas com o DefaultTableModel?

No fundo, usa-lo é ferir bons modelos, como o MVC. É ter trabalho extra à toa e aumentar os custos de produção e manutenção do sistema.
Você não sai por aí recomendando que as pessoas não dividam o software em camadas, sai?

Ou dizendo que programadores júniores, por serem júniores, tem o direito de sair fazendo sistema de qualquer jeito, diz?

É a mesma coisa com o DefaultTableModel. Estamos falando em aboli-lo de desenvolvimento profissional. Acho impressionante que muita gente aqui gasta esforço real criando DAOs, Controllers, dividindo a View mas, não sei por que, chega na hora do TableModel, fica resistente em aprender algo tão simples. Já vi mais de um caso desse no GUJ.

Para fins didáticos, ele pode até ser usado como exemplo, mas só. O problema é quando algum recurso didático é tão pobre, e tão ruim, que você no fundo está deseducando ao invés de educar.

[quote=ViniGodoy][quote=SneepS]Então galera, já fazem muitos anos que venho acompanhando o GUJ, acho que desde 2003 quando entrei na faculdade.
Na área de programação já é quase 10 anos, tenho muita intimidade com java swing, e acho que posso dar um parecer técnico ao meu ponto de vista.

O DefaultTabelModel não pode, nem deve ser morto, ele é o feijão com arroz, o básico onde as pessoas usam sem entender para fazer funcionar o básico de uma tabela.

Quando a pessoa passa por uma situação diferente tipo colocar imagem, jProgressBar dentro da tabela, a pessoa estuda o caso mais a fundo.
Ai sim passa a entender o funcionamento de um model e vai implementar um com esses exemplos todos que estão rolando por aqui no forum.

É ótimo os exemplos, eu os uso, mas para quem esta no javaBaby, tem que começar de algo básico e ir progredindo.

Abraços![/quote]

E quem paga o custo da manutenção das tabelas deixadas com o DefaultTableModel?

No fundo, usa-lo é ferir bons modelos, como o MVC. É ter trabalho extra à toa e aumentar os custos de produção e manutenção do sistema.
Você não sai por aí recomendando que as pessoas não dividam o software em camadas, sai?

Ou dizendo que programadores júniores, por serem júniores, tem o direito de sair fazendo sistema de qualquer jeito, diz?

É a mesma coisa com o DefaultTableModel. Estamos falando em aboli-lo de desenvolvimento profissional. Acho impressionante que muita gente aqui gasta esforço real criando DAOs, Controllers, dividindo a View mas, não sei por que, chega na hora do TableModel, fica resistente em aprender algo tão simples. Já vi mais de um caso desse no GUJ.

Para fins didáticos, ele pode até ser usado como exemplo, mas só. O problema é quando algum recurso didático é tão pobre, e tão ruim, que você no fundo está deseducando ao invés de educar.[/quote]

Ai sim Vini, quem atua profissionalmente deve aprender, ir a fundo no que esta fazendo, não simplesmente copiar o codigo de alguem, deve compreender o que o codigo esta fazendo e deve se possivel melhora-lo com as melhores práticas da programação como estas que tu citou.

Mas, como eu disse, aprender é um passo de cada vez, ir aumentando o nivel da programação gradualmente, quem esta na fase de primeiro contato com JAVA, mal entende orientação a objeto, muito menos o conceito de MVC.

Mas, você me convenceu…rsrsr. Se no primeiro contato com uma table o cara já aprende-se junto a implementar um model seria um “adiantamento” na vida de quem esta aprendendo.

Finalmente consegui entender quando me diziam "você deve construir um modelo para tabela primeiro"
Com base nos teus codigos, consegui desenvolver um modelo para uma tabela que vou usar depois numa janela, ficou muito bom, testei criando uma classe parecida com o seu que testa o modelo, e funcionou muito melhor do que eu esperava.

Parece que vou entrar para esse grupo dos Morte ao DefaultTableModel!

[quote=Blaquicat]Finalmente consegui entender quando me diziam "você deve construir um modelo para tabela primeiro"
Com base nos teus codigos, consegui desenvolver um modelo para uma tabela que vou usar depois numa janela, ficou muito bom, testei criando uma classe parecida com o seu que testa o modelo, e funcionou muito melhor do que eu esperava.

Parece que vou entrar para esse grupo dos Morte ao DefaultTableModel![/quote]
Valeu. Fico feliz que o exemplo tenha auxiliado no entendimento. :smiley:

Atualizei o primeiro post, adicionando um link para um artigo com uma explicação melhor sobre o assunto: http://devsv.wordpress.com/2012/07/08/como-implementar-um-tablemodel/.

Atualizei o post que o link da minha assinatura referencia para incluir esse seu artigo também. Ficou muito bom!

Obrigado pela referência, ViniGodoy.

Pessoal,

segue exemplo simples de um TableModel “genérico”. Talvez ajude alguém:

public abstract class SimpleTableModel<T> implements TableModel {
    
    protected List<String> columnNames;
    protected List<Class> columnTypes;
    private List<TableModelListener> listeners;

    public SimpleTableModel(Class<T> type) {
        columnNames = new ArrayList<String>();
        columnTypes = new ArrayList<Class>();
        listeners = new ArrayList<TableModelListener>();
        initFromType(type);
    }
    
    protected void initFromType(Class<T> type) {
        
        Method[] metodos = type.getMethods();
        
        Map<String, Class> columns = new HashMap<String, Class>();
        
        for (Method m : metodos) {
            
            if((m.getName().startsWith("get") || m.getName().startsWith("is")) && ! m.getName().equals("getClass")) {
                
                int offset = m.getName().startsWith("get") ? 3 : 2;
                
                columnNames.add(m.getName().substring(offset));
                columnTypes.add(m.getReturnType());
                
            }
            
        }
        
    }

    protected abstract List<T> getValues();

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        
        if(columnIndex < 0 || columnIndex >= columnTypes.size()) {
            throw new IndexOutOfBoundsException("Índice " + columnIndex + " inválido");
        }
        
        if(rowIndex < 0 || rowIndex >= getValues().size()) {
            throw new IndexOutOfBoundsException("Índice " + rowIndex + " inválido");
        }
        
        T value = getValues().get(rowIndex);
        
        Class type = value.getClass();
        
        Method[] allMethods = type.getMethods();
        
        //List<Method> setters = new ArrayList<Method>();
        Map<String, Method> setters = new HashMap<String, Method>();
        List<Method> getters = new ArrayList<Method>();
        
        for (Method m : allMethods) {
            
            if(m.getName().startsWith("set")) {
                
                setters.put(m.getName().substring(3), m);
                
            } else if((m.getName().startsWith("get") || m.getName().startsWith("is")) && ! m.getName().equals("getClass")) {
                getters.add(m);
            }
            
        }
        
        String methodName = getters.get(columnIndex).getName();
        
        if(methodName.startsWith("is")) {
            methodName = methodName.substring(2);
        } else {
            methodName = methodName.substring(3);
        }
        
        T object = getValues().get(rowIndex);
        
        try {
            Method setter = setters.get(methodName);
            setter.invoke(object, aValue);
            fireTableChange(new TableModelEvent(this));
        } catch (Exception e) {
            throw new RuntimeException("Falha ao definir valor na tabela", e);
        }
        
    }
    
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        
        if(columnIndex < 0 || columnIndex >= columnTypes.size()) {
            throw new IndexOutOfBoundsException("Índice " + columnIndex + " inválido");
        }
        
        if(rowIndex < 0 || rowIndex >= getValues().size()) {
            throw new IndexOutOfBoundsException("Índice " + rowIndex + " inválido");
        }
        
        T value = getValues().get(rowIndex);
        
        Class type = value.getClass();
        
        Method[]  allMethods = type.getMethods();
        
        List<Method> methods = new ArrayList<Method>();
        
        for (Method m : allMethods) {
            if((m.getName().startsWith("get") || m.getName().startsWith("is")) && ! m.getName().equals("getClass")) {
                methods.add(m);
            }
        }
        try {
            return methods.get(columnIndex).invoke(value);
        } catch (Exception ex) {
            throw new RuntimeException("Falha ao pegar valor em célula da tabela", ex);
        } 
        
    }
    
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        
        if(columnIndex < 0 || columnIndex >= columnTypes.size()) {
            throw new IndexOutOfBoundsException("Índice " + columnIndex + " inválido");
        }
        
        return columnTypes.get(columnIndex);
        
    }

    @Override
    public String getColumnName(int columnIndex) {
        if(columnIndex < 0 || columnIndex >= columnNames.size()) {
            throw new IndexOutOfBoundsException("Índice " + columnIndex + " inválido");
        }
        
        return columnNames.get(columnIndex);
        
    }

    @Override
    public int getColumnCount() {
        return columnNames.size();
    }
    
    @Override
    public void addTableModelListener(TableModelListener l) {
        listeners.add(l);
    }

    @Override
    public void removeTableModelListener(TableModelListener l) {
        listeners.remove(l);
    }
    
    protected void fireTableChange(TableModelEvent evt) {
        for (TableModelListener l : listeners) {
            l.tableChanged(evt);
        }
    }
    
}

Infelizmente, esse esquema força que as implementações desse TableModel sempre o construam passando a classe do tipo manipulado! Existe jeito de não precisar disso?
Ps. Não dei atenção para o disparo de eventos… Pode ser melhor definido.

Obrigado e abraços!