Adicionar colunas a TableModel personalizado [RESOLVIDO]

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.

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

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).

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.

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.

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).

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

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:

[code]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 cabecalho = new ArrayList();
private List<List> linhas = new ArrayList();
private List 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());
    }
}

}
[/code]

Formulario com a tabela:

[code]
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 cabecalho;
ArrayList 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);

}
}[/code]

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.

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.

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

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);
   }