Table model

Boa noite a todos.

Conforme orientações recebidas nesse forum, dicidi implementar minha propria TableModel. Mas fico com uma dúvida quando ao modo como a fiz: as minhas classes descendem de uma classe base, que chamo de Base. Criei um TableModel, extendendo AbstractTableModel, que tem um ArrayList dessa classe base e os métodos para buscar e incluir registros usam objetos desse tipo. Não implementei o getValueAt, deixando o mesmo para ser implementado na hora de instanciar um objeto de minha TableModel. Essa é uma bota prática? Ou teria que para cada classe criar um TableModel novo, ou seja, uma para Cidade, um para Cliente, um para Venda…?

Depende. Que tipo de dados serão inseridos na tabela? Os mesmos para todas as classes?

Talvez seu TableModel possa refletir a hierarquia que você tem. Ou seja, ter um tablemodel base, e classes derivadas, para as colunas específicas.

Por isso models como o do Marky, bastante automáticos, também são interessantes. O uso de reflexão dele evita uma explosão de classes. Com o model que propus no tópico do TableFilter ainda se faz muitas classes, mas são mais simples do que as do TableModel comum.

Serão mostrados os dados para as telas de consulta. A minha dúvida é se realmente é necessário criar uma TableModel para Cliente, uma para Fornecedor, uma para Venda … Não posso criar uma TableModel que servirá para todas as situações? Nessa TableModel tenho todos os métedos já impelmentados, menos o getValueAt. Esse método eu implementaria ao instanciar o objeto.

Minha classe TableModel:

[code]package jvendas.modelos;

import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;
import jvendas.classes.Base;

public abstract class ModeloTabela extends AbstractTableModel {
private ArrayList rows;
private String[] columnNames;

public ModeloTabela(String[] columnNames) {
    rows = new ArrayList<Base>();
    this.columnNames = columnNames;
}

public ModeloTabela(ArrayList registros, String[] columnNames) {
    this.rows = new ArrayList<Base>();
    addRows(registros);
    this.columnNames = columnNames;
}

@Override
public String getColumnName(int column) {
    return columnNames[column];
}

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

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

public Base getRow(int rowIndex) {
    return (Base) rows.get(rowIndex);
}

public void setRow(int rowIndex, Base row) {
    rows.set(rowIndex, row);
    fireTableRowsUpdated(rowIndex, rowIndex);
}

public void addRow(Base row) {
    rows.add(row);
    fireTableRowsInserted(rows.size() -1, rows.size() - 1);
}

public void removeRow(int rowIndex) {
    rows.remove(rowIndex);
    fireTableRowsDeleted(rowIndex, rowIndex);
}

public void addRows(ArrayList rows) {
    this.rows.addAll(rows);
    fireTableRowsInserted(0, rows.size() - 1);
}

public abstract Object getValueAt(int rowIndex, int columnIndex);

}[/code]

Exemplo de uso na tela de consulta de bancos:

[code] setModelo(new ModeloTabela(new String[] {“Nome”, “Código”}) {
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Banco banco = (Banco) getRow(rowIndex);

            if (banco == null) {
                return null;
            } else {
                String coluna = getColumnName(columnIndex);

                if (coluna.equalsIgnoreCase("Nome")) {
                    return banco.getNome();
                } else if (coluna.equalsIgnoreCase("Código")) {
                    return banco.getCodigo();
                } else {
                    return null;
                }
            }
        }
    });[/code]

Exemplo de uso na tela de consulta de agências:

[code] setModelo(new ModeloTabela(new String[] {“Banco”, “Nome”, “Número”}) {

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            Agencia agencia = (Agencia) getRow(rowIndex);

            if (agencia == null) {
                return null;
            } else {
                String coluna = getColumnName(columnIndex);

                if (coluna.equalsIgnoreCase("Banco")) {
                    return agencia.getBanco().getNome();
                } else if (coluna.equalsIgnoreCase("Nome")) {
                    return agencia.getNome();
                } else if (coluna.equalsIgnoreCase("Número")) {
                    return agencia.getNumero();
                } else {
                    return null;
                }
            }
        }
    });[/code]

Gostaria de saber se isso é uma bota pratica, se não é uma gambiarra

Até pode sim, mas como vc fará com as colunas específicas de cada subclasse? Vai testar por instanceof?
Ou vai estender esse model, criando um filho mais simples (e, nesse caso, terminar com a árvore muito parecida com a de suas classes).

As colunas eu tenho que definir ao dar o new no objeto ModeloTabela, veja que há dois métodos construtores, ambos precisam receber as colunas, e mantenho o método getValueAt abstrato mesmo na classe ModeloTabela. Ao dar o new tenho que implementar esse médodo, ai defino as colunas e a informação que cada uma mostrará. A vatagem é que o TableModel fica bem maleável, posso usar em várias situações. Por exemplo, na tela de consulta a agências bancárias, tenho uma table para listar as agências cadastradas (nome, banco, número) e no consulta de bancos tenho uma table para listar as agências de cada banco (somente nome). Ok?

Só uma dúvida. Pq vc não declara a sua variável como:

Ia evitar a maioria daqueles casts.

Até cheguei a fazer isso, mas dá problema nesse método:

public void addRows(ArrayList<Base> rows) { this.rows.addAll(rows); fireTableRowsInserted(0, rows.size() - 1); }

A não ser que ao invés de passar um ArrayList eu passe sempre um ArrayList, porém nesse ArrayList carrego objetos do tipo Banco. É isso?

A solução é passar um arrayList de base, ou de qualquer coisa que estenda base:

public void addRows(ArrayList&lt;? extends Base&gt; rows) { this.rows.addAll(rows); fireTableRowsInserted(0, rows.size() - 1); }

Agora o método aceita um ArrayList<Base>, ArrayList<Banco> ou de qualquer outro filho de Base.