Qual o problema da minha AbstractTableModel?

10 respostas
lordExorcist

Qual o problema da minha AbsctractTableModel?

Minha classe que estende AbstractTableModel recebe parâmetros para preenchimento das colunas e das linhas como vetores.

A primeira coluna é formada por booleans que se tornam check-boxes. O problema é: quando seleciono uma célula que é editável (isto é, o método isCellEditable(int row, int col){…} retorna true para tal célula) e depois uma célula da 1ª coluna, esta se deforma.

Isso não acontece quando a célula selecionada antes da célula da 1ª coluna é não-editável (isto é, o método isCellEditable(int row, int col){…} retorna false).
Falta configurar alguma coisa? =(

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

public class MyTableModel extends AbstractTableModel {
  
  private Vector rows;
  private Vector columns;
  
  // construtor 1:
  public MyTableModel() {
    setRows(new Vector(1, 1));
    setColumns(new Vector(1, 1));
  }
  
  // construtor 2:
  public MyTableModel(Vector rows, Vector columns) {
    this.rows = rows;
    this.columns = columns;
  }
  
  public int getRowCount() {
    return rows.size();
  }
  
  public int getColumnCount() {
    return getColumns().size();
  }
  
  public String getColumnName(int col) {
    return String.valueOf(getColumns().get(col));
  }
  
  public Class getColumnClass(int col) {
    return getValueAt(0, col).getClass();
  }
  
  public Object getValueAt(int row, int col) {
    return ((Vector) getRows().get(row)).get(col);
  }
  
  public void setValueAt(Object value, int row, int col) {
    ((Vector) getRows().get(row)).setElementAt(value, row);
    fireTableCellUpdated(row, col);
  }
  
  public boolean isCellEditable(int row, int col) {
    return false;
    //return true;
  }
  
  public Vector getRows() {
    return rows;
  }

  public void setRows(Vector rows) {
    this.rows = rows;
    this.fireTableRowsUpdated(0,  rows.size());
  }

  public Vector getColumns() {
    return columns;
  }

  public void setColumns(Vector columns) {
    this.columns = columns;
    this.fireTableDataChanged();
  }
  
}  //FIM DA CLASSE.

O código abaixo é executado quando um botão é pressionado:

JTable table = new JTable();
    ...
    MyTableModel mtm = new MyTableModel();
    Vector columns = new Vector(1, 1);
    columns.add("Remover?");
    columns.add("Matrícula");
    columns.add("Nome");
        
    Vector rows = new Vector(1, 1);
    Vector row = new Vector(1, 1);
    row.add(new Boolean(true));
    row.add("[telefone removido]-7");
    row.add("Antonioni de Araújo Rocha");
    rows.add(row);
    
    mtm.setRows(rows);
    mtm.setColumns(columns);
    table.setModel(mtm);
    table.getColumnModel().getColumn(0).setMaxWidth(70);
    table.repaint();

A tabela aparece perfeita.

Quando a tabela aparece, está perfeita:

Se seleciono uma célula qualquer que é editável, …

… e depois uma célula da 1ª coluna (editável ou não), esta se deforma com o valor da célula anterior:

Isto não ocorre se as células são não-editáveis:

Gurus do JTable, help…

10 Respostas

keller

Cara aqui nao tenho nenhum exemplo mas os exemplos que haviam na pgina da senun devem te ajudar em muita coisa… faça o download e de uma lida no conteudo!

Swing Examples

beleza ? até…

lordExorcist

Hei, gui, valeu o link… vai ser utilíssimo!! :smiley:

Porém acabei de achar e consertar o erro… :lol:
O método

public void setValueAt(Object value, int row, int col) {
    ((Vector) getRows().get(row)).setElementAt(value, row);
    fireTableCellUpdated(row, col);
  }

é

public void setValueAt(Object value, int row, int col) {
    ((Vector) rows.get(row)).set(col, value);
    fireTableCellUpdated(row, col);
  }

Em vez de Vector.setElementAt(…), deve ser [b]Vector.set/b !!! :shock:

Falta de paciência é f* …

lordExorcist

… continuo aperfeiçoando minha classe MyTableModel, e estou com outro problema:

No frame que popula a tabela cujo model é um objeto MyTableModel, tenho, no momento de contrução da tabela:

JTable table = new JTable();
...
MyTableModel mtm = new MyTableModel();
Vector linhas = new Vector(), //vetor de linhas
          linha = new Vector(), //representa uma linha
          colunas = new Vector(); //vetor de colunas

colunas.add("col1");
colunas.add("col2");
linha.add("lin1");
linha.add("lin2");
linhas.add(linha);

mtm.setColumns(colunas);
mtm.setRows(linhas);

table.setModel(mtm);

Se uso este código, a tabela tb é populada e renderizada perfeitamente.

Mas se tento o código abaixo, no mesmo evento de botão:

...
linhas.removeAllElements();
linha.removeAllElements();
linha.add("novaLin1");
linha.add("novaLinl2");
linhas.add(linha);

mtm.setColumns(colunas);
table.validate();
table.repaint();

A tabela é populada mas não é renderizada. Tanto que quando minimizo e maximizo o frame, ela aparece com as linhas atualizadas.
Há algum método que a tabela ou o model deve disparar para a repintagem da tabela seja automática? :-o

brlima

Pelo que pude perceber vc tá trabalhando direto com o vetor na memoria. Isso nao deixa pistas pro modelo de que ele esta sendo alterado, consequentemente, a JTable não vai se atualizar.
Recomendo que crie novos metodos no modelo que façam o trabalho de apagar as linhas dele e para incluir linhas, e que estes métodos disparem os eventos certos para atualização do JTable a qual pertence o table model.

Sugestões:

public void removeAllLines(){
   getRows().removeAll();
   fireTableChanged(null);
}
public void addLine(Vector line){
   getRows().add(line);
   fireTableChanged(null);
}

Só confirma os métodos de disparo de eventos ( fireTable… ) pois pra cada coisa que vc faz nela tem um, so nao lembro direito a assinatura :smiley: Consulta na API. :smiley: Deve ter um fireTableRowInserted e fireTableRowDeleted.

flw!

lordExorcist

brlima:
Pelo que pude perceber vc tá trabalhando direto com o vetor na memoria. Isso nao deixa pistas pro modelo de que ele esta sendo alterado, consequentemente, a JTable não vai se atualizar.
Recomendo que crie novos metodos no modelo que façam o trabalho de apagar as linhas dele e para incluir linhas, e que estes métodos disparem os eventos certos para atualização do JTable a qual pertence o table model.

Sugestões:

public void removeAllLines(){
   getRows().removeAll();
   fireTableChanged(null);
}
public void addLine(Vector line){
   getRows().add(line);
   fireTableChanged(null);
}

Só confirma os métodos de disparo de eventos ( fireTable… ) pois pra cada coisa que vc faz nela tem um, so nao lembro direito a assinatura :smiley: Consulta na API. :smiley: Deve ter um fireTableRowInserted e fireTableRowDeleted.

flw!


Ok, fiz isso, e encontrei os métodos: fireTableDataChanged() e fireTableStructureChanged(). Bem, funcionou! :smiley:

Agora apareceu mais uma dúvida: o método getColumnCount() definido abaixo retorna nulo quando uso o contrutor com vetores como argumento, mesmo quando os vetores passados não são nulos. Se eu utilizar o setColumns(Vector columns), funciona.
Por que será? :frowning:

public MyTableModel(Vector rows, Vector columns) {
    setRows(rows);
    setColumns(columns);
    
    setEnabledRows(new int[0]);
    setEnabledColumns(new int[0]);
    setRowsAndColumnsToEnableRespected(true);
    setAllCellsDisabled(true);
    fireTableStructureChanged();
  }
...
public int getColumnCount() {
  return getColumns().size();
}

 public Vector getColumns() {
    return columns;
  }

  public void setColumns(Vector columns) {
    if(columns != null) this.columns = columns;
    else this.columns = new Vector(1, 1);
    
    fireTableStructureChanged();
  }
brlima

Posso até tá cego, mas não to vendo nada de errado no teu codigo… :roll:
A não ser que dentro de algum daqueles métodos deus que seguem dentro do contrutor, logo apos o setCOlumns() zera a variavel columns.

Veriqfique se a instancia do model que vc tá criando é a mesma que vc esta chamando o getColumnCount().

É o que imagino que pode ser… :wink:

flw!

lordExorcist

brlima:
Posso até tá cego, mas não to vendo nada de errado no teu codigo… :roll:
A não ser que dentro de algum daqueles métodos deus que seguem dentro do contrutor, logo apos o setCOlumns() zera a variavel columns.

Veriqfique se a instancia do model que vc tá criando é a mesma que vc esta chamando o getColumnCount().

É o que imagino que pode ser… :wink:

flw!


Pior que é… ela é uma instância global… :frowning:

brlima

Então toma cuidado pra não acessar uma local com mesmo nome de global sem perceber.

lordExorcist

Não se preocupe… isso não está acontecendo… só existe um objeto MyTableModel (atm) em todo o frame… :frowning:

lordExorcist

Ahhhhhhhhhhhhhh…
Até que enfim, consertei :smiley: :smiley: :smiley:

Depois de fuçar, apagar, copiar/colar e compilar, saiu:

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

/**
 *
 * @author Antonioni de Araújo Rocha
 */
public class MyTableModel extends AbstractTableModel {
  
  private Vector rows;
  private Vector columns;
  private int[] editableRows;
  private int[] editableColumns;
  private boolean respectRowsAndColumnsToEnable;
  private boolean allCellsEditable;
  private boolean rowsSetted;
  private boolean columnsSetted;
  
  /** Creates a new instance of MyTableModel */
  public MyTableModel() {
    setAttributes(rows, columns, false, false);
  }
  
  public MyTableModel(Vector rows, Vector columns) {
    setAttributes(rows, columns, true, true);
  }
  
  private void setAttributes(Vector rows, Vector columns, boolean rowsSetted, boolean columnsSetted) {
    setColumns(columns);
    setRows(rows);
    setEditableRows(new int[0]);
    setEditableColumns(new int[0]);
    setEditableRowsAndColumnsRespected(true);
    setAllCellsEditable(false);
    rowsSetted = true;
    columnsSetted = true;
  }
  
  private Vector nonNullVector(Vector v) {
    return (v != null) ? v : new Vector(1, 1);
  }
  
  private Vector justifyRow(Vector row) {
    row = nonNullVector(row);
    if(row.size() > getColumns().size()) row.setSize(getColumns().size());
    return row;
  }
  
  private void justifyEditableRows() {
    if(getEditableRows() != null) {
      if(getEditableRows().length > getRowCount()) {
        int[] actualEditableRows = getEditableRows();
        this.editableRows = new int[getRowCount()];
        for(int i=0; i<getRowCount(); i++) getEditableRows()[i] = actualEditableRows[i];
      }
    }
  }
  
  private void justifyEditableColumns() {
    if(getEditableColumns() != null) {
      if(getEditableColumns().length > getColumnCount()) {
        int[] actualEditableColumns = getEditableColumns();
        this.editableColumns = new int[getColumnCount()];
        for(int i=0; i<getColumnCount(); i++) getEditableColumns()[i] = actualEditableColumns[i];
      }
    }
  }
  
  public int getRowCount() {
    return getRows().size();
  }
  
  public int getColumnCount() {
    return getColumns().size();
  }
  
  public String getColumnName(int col) {
    Object id = null;
    if(col &gt;< columns.size()) id = columns.elementAt(col);
    return (id == null) ? super.getColumnName(col) : id.toString();
  }
  
  public Class getColumnClass(int col) {
    return getValueAt(0, col).getClass();
  }
  
  public Object getValueAt(int row, int col) {
    try {
      return ((Vector) getRows().elementAt(row)).elementAt(col);
    }
    catch(ArrayIndexOutOfBoundsException aioobe) {
      return new String();
    }
  }
  
  public void setValueAt(Object value, int row, int col) {
    try {
      if(value != null) ((Vector) getRows().elementAt(row)).setElementAt(value, col);
      else ((Vector) getRows().elementAt(row)).setElementAt(new String(), col);
    }
    catch(ArrayIndexOutOfBoundsException aioobe) {
      ((Vector) getRows().elementAt(row)).addElement(new String());
    };
    
    fireTableCellUpdated(row, col);
  }
  
  public boolean isCellEditable(int row, int col) {
    if(areAllCellsEditable()) {
      return true;
    }
    else if(areEditableRowsAndColumnsRespected()) {
      boolean editableRow = false, editableColumn = false;

      if(getEditableRows().length > 0) {
        for(int i=0; i&lt;getEditableRows().length; i++) {
          if(row == getEditableRows()[i]) {
            editableRow = true;
            break;
          }
        }
      };

      if(getEditableColumns().length &gt; 0) {
        for(int i=0; i&lt;getEditableColumns().length; i++) {
          if(col == getEditableColumns()[i]) {
            editableColumn = true;
            break;
          }
        }
      };
      
      return (editableRow || editableColumn);
    };
    
    return false;
  }
  
  public void removeData() {
    rows.removeAllElements();
    fireTableDataChanged();
  }
  
  public void clear() {
    rows.removeAllElements();
    columns.removeAllElements();
    fireTableStructureChanged();
  }
  
  public Vector getRows() {
    return rows;
  }

  public void setRows(Vector rows) {
    this.rows = nonNullVector(rows);
    rowsSetted = true;
    
    if(columnsSetted)
      for(int i=0; i&gt;&lt;getRows().size(); i++) justifyRow((Vector) getRows().elementAt(i));
    
    justifyEditableRows();
    fireTableStructureChanged();
  }

  public Vector getColumns() {
    return columns;
  }

  public void setColumns(Vector columns) {
    this.columns = nonNullVector(columns);
    columnsSetted = true;
    justifyEditableColumns();
    fireTableStructureChanged();
  }
  
  public void setRowsAndColumns(Vector rows, Vector columns) {
    setColumns(columns);
    setRows(rows);
  }

  public int[] getEditableRows() {
    return editableRows;
  }

  public void setEditableRows(int[] editableRows) {
    this.editableRows = editableRows;
    if((getRows() != null) && rowsSetted) justifyEditableRows();
  }
  
  public int[] getEditableColumns() {
    return editableColumns;
  }
  
  public void setEditableColumns(int[] editableColumns) {
    this.editableColumns = editableColumns;
    if((getColumns() != null) && columnsSetted) justifyEditableColumns();
  }
  
  public boolean areEditableRowsAndColumnsRespected() {
    return respectRowsAndColumnsToEnable;
  }
  
  public void setEditableRowsAndColumnsRespected(boolean respectRowsAndColumnsToEnable) {
    this.respectRowsAndColumnsToEnable = respectRowsAndColumnsToEnable;
  }
  
  public boolean areAllCellsEditable() {
    return allCellsEditable;
  }
  
  public void setAllCellsEditable(boolean allCellsEditable) {
    this.allCellsEditable = allCellsEditable;
  }

}

Funciona que é uma beleza.

Criado 10 de janeiro de 2005
Ultima resposta 19 de jan. de 2005
Respostas 10
Participantes 3