Adicionar colunas a TableModel personalizado [RESOLVIDO]

11 respostas
L

Bom dia pessoal!

Fiz algumas buscas ao GUJ, mas não encontrei nada relativo a este assunto. Tenho meu table modelo personalizado (exemplo ViniGodoy), porém necessito adicionar colunas dinamicamente, e não sei como fazer. Se alguém puder repassar um exemplo, agradeço.

Abraço.

11 Respostas

E

Você realmente precisa adicionar uma coluna, ou é suficiente simplesmente esconder a coluna e mudar o título?

L

Obrigado por retornar entanglement . Realmente necessito adiciona-las em tempo de execução. Isto de acordo com os paramentros do item que foi selecionado pelo usuário (JComboBox).

E

Nesse caso, provavelmente você terá de criar um TableModel que seja um ArrayList de ArrayLists (não exatamente um ArrayList de objetos de uma determinada classe, que é o padrão para as tabelas com TableModel personalizado).

Uma vez que você chamou o combo, as colunas da tabela poderão ser alteradas ou não? (Por exemplo, ele é um retorno de uma consulta SQL que você escolheu via combo?)

Se o combo tiver poucas alternativas e a cada alternativa estiver associada uma determinada classe, você pode criar um TableModel diferente para cada alternativa, e então associar dinamicamente esse TableModel ao JTable.

L

Tanto os itens listados no combo, como os parametros, determinam as colunas exibidas são retornados de uma query. A quantidade de colunas “adicionais” que posso necessitar pode variar de 0 a 15, podendo gerar inúmeras combinações de colunas. Andei observando a classe DefaultTableModel (infelizmente) e a mesma possui os metodos para adicionar ou remover colunas, mas estou tentando evitar o uso da mesma. Muito obrigado pela resposta Sr. entanglement. Abraço.

E

No seu caso, talvez fosse mais fácil ter um ArrayList de ArrayList. Não use DefaultTableModel porque ele é um Object[][], o que indica que você não consegue adicionar linhas de maneira trivial (você se lembra que um array não pode ser expandido ou diminuído).

L

Certo, vou tentar implementa-lo, muito obrigado. Talvez, possui algum exemplo?

A

Leonardo,

Segue um exemplo. Fiz alguns testes, mas como implementei a pouco tempo acho que ainda precisa testar mais. Pode melhorar ainda. Por exemplo: podem ser adicionados métodos para remover linhas e colunas.

entanglement, é isto mesmo que você estava sugerindo?

TableModel:

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

public class ModelFlex extends AbstractTableModel {
    private List<String> cabecalho = new ArrayList();
    private List<List<Object>> linhas = new ArrayList();
    private List<Class> classes = new ArrayList();

    public ModelFlex(ArrayList<String> cabecalho, ArrayList<Class> classes){
       if(cabecalho.size() != classes.size()){
           throw new IllegalArgumentException("Quantidade de colunas diferente da quantidade de classes.");
       }
       this.cabecalho = (List<String>) cabecalho.clone();
       this.classes = (List<Class>) classes.clone();
    }

    public String getColumnName(int col){
        return cabecalho.get(col);
    }

    public int getRowCount(){
       return linhas.size(); 
    }
    
    public int getColumnCount() {
       return cabecalho.size();
    }
    
    public Object getValueAt(int row, int col) {
        return linhas.get(row).get(col);
    }

    public Class getColumnClass(int col) {
        return classes.get(col);
    }
    
    public void addRow(ArrayList<? extends Object> valores){
        if(valores.size() != cabecalho.size()){
           throw new IllegalArgumentException("Quantidade de valores diferente da quantidade de colunas.");
        }
        for(int coluna=0; coluna<valores.size(); coluna++){
           validar(coluna, valores.get(coluna));
        }
        ArrayList<Object> linha = new ArrayList();
        for(Object valor: valores){
           linha.add(valor);
        }
        linhas.add(linha);
        fireTableDataChanged();
    }

    public void addColumn(String titulo, Class classe){
        //adiciono a nova coluna no cabecalho
        cabecalho.add(titulo);

        //adiciono a classe da nova coluna
        classes.add(classe);

        //adiciono os valores da nova coluna em cada linha
        for(List<Object> valores: linhas){
            try{
               valores.add( classe.newInstance() );
            }catch(ReflectiveOperationException ex){
               throw new IllegalArgumentException("Nao foi possivel instanciar a classe " + classe.getName() );
            }
        }
        fireTableStructureChanged();
    }

    //cria uma coluna com valor default
    public void addColumn(String titulo, Class classe, Object valorDefault){
        //adiciono a nova coluna no cabecalho
        cabecalho.add(titulo);

        //adiciono a classe da nova coluna
        classes.add(classe);

        //adiciono os valores da nova coluna em cada linha
        for(List<Object> valores: linhas){
            valores.add( valorDefault );
        }
        fireTableStructureChanged();
    }

    private void validar(int col, Object valor) {
        if(!valor.getClass().equals(classes.get(col))){
           throw new IllegalArgumentException("Valor na coluna " + col + 
           " deve ser do tipo " + classes.get(col).toString());
        }
    }
}
Formulario com a tabela:
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;

public class FormTabela extends JFrame{
  ModelFlex model;
  final JTable tabela;
  ArrayList<String> cabecalho;
  ArrayList<Class> classes;
  int quantLinhas = 0;

  public static void main(String[] args) {
     FormTabela ft = new FormTabela();
     ft.setVisible(true);
  }

  public FormTabela(){
    super("Tabela que permite incluir colunas");	

    Container c = getContentPane();
    c.setLayout(new FlowLayout());

    cabecalho = new ArrayList();
    cabecalho.add("Codigo");
    cabecalho.add("Telefone");

    classes = new ArrayList();
    classes.add(Integer.class);
    classes.add(String.class);

    model = new ModelFlex(cabecalho, classes);
    tabela = new JTable(model);
    tabela.setPreferredScrollableViewportSize(new Dimension(450, 200));
			
    JScrollPane scrollPane = new JScrollPane(tabela);
    c.add(scrollPane);
    
    JButton incluirLinha = new JButton("Incluir Linha");
    incluirLinha.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                ArrayList<Object> linha = new ArrayList();
                quantLinhas++;
                for(int coluna = 0; coluna<cabecalho.size(); coluna++){
                   if(classes.get(coluna).equals(String.class)){
                      linha.add(cabecalho.get(coluna) + " " + quantLinhas);
                   }else if(classes.get(coluna).equals(Integer.class)){
                      linha.add(new Integer(quantLinhas));
                   }
                }
                model.addRow(linha);
            }
    });
    c.add(incluirLinha);

    JButton incluirColuna = new JButton("Incluir Coluna");
    incluirColuna.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                String nome = JOptionPane.showInputDialog(null, "Digite o nome da nova coluna:");
                if(nome != null){
                   cabecalho.add(nome);
                   classes.add(String.class);
                   model.addColumn(nome, String.class);
                }
            }
    });
    
    c.add(incluirColuna);
    setSize(500, 400);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
  }
}
L

Alcebiades, o salvador da Pátria, hehe.
Exatamente isto que precisava, testei, funcionou perfeitamente, agora irei adaptar ao projeto. Parabéns, e obrigado pela resposta. Tópico resolvido.

L

Reabrindo o tópico. Necessito implementar o metodo setValueAt(Object aValue, int rowIndex, int columnIndex). Tentei deste modo, os valores chegam ao metodo corretamente, mas os valores não são alterados no model. Alguém tem ideia como fazer?

@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
   super.setValueAt(aValue, rowIndex, columnIndex);
   fireTableDataChanged();
}

Obs.: A classe extends a AbstractTableModel.
Obrigado.

F

Você tem que implementar esse método, alterando algo no objeto da linha x e coluna y.

L

Obrigado pela resposta fasts. Acabei encontrando a solução.

@Override
   public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
      List rowData = linhas.get(rowIndex);  //List<List<Object>> linhas
      rowData.set(columnIndex, aValue);
      fireTableCellUpdated(rowIndex, columnIndex);
   }
Criado 10 de julho de 2012
Ultima resposta 12 de jul. de 2012
Respostas 11
Participantes 4