Re:Ação no modelo de JTable

8 respostas
ViniGodoy

Por que na implementação do seu setValueAt do model você não altera os dois valores?

8 Respostas

ViniGodoy
diogoroos:
Exceção de índice... vou colocar novamente o TableModelListener para ver exatamente o erro e posto. Você teria um exemplo para eu ver se estou fazendo da maneira correta ? -Valeu pela atenção.

Como assim "exceção de índice". Você tem um model próprio?

A idéia é atualizar duas propriedades do seu objeto, ao invés de uma. Então é só fazer isso!
public class SampleTableModel extends AbstractTableModel

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    if (columnIndex == COL_VALOR_ORIGINAL) {
            valores.get(rowIndex).setValorOriginal((Double)value);
            valores.get(rowIndex).setValorAberto((Double)value);
    }
}

Valores seria um JList com sua classe, seja ela qual for.

ViniGodoy

Basta fazer:

public class SampleTableModel extends AbstractTableModel  {
  
   public void setValueAt(Object aValue, int rowIndex, int columnIndex) {   
       if (columnIndex == COL_VALOR_ORIGINAL) {   
               valores.get(rowIndex).setValorOriginal((Double)value);   
              valores.get(rowIndex).setValorAberto((Double)value);   
      }   
   }  

   public Class <?> getColumnClass(int columnIndex) {
       if (columnIndex == COL_CHECK) //Índice da coluna com checkbox
          return Boolean.class;
       return Object.class; //Demais colunas
    }
}

Não deixe de ler esses ótimos artigos sobre o assunto:
http://www.informit.com/articles/article.aspx?p=332278
http://www.informit.com/articles/article.aspx?p=333472

Você não vai se arrepender. Usar um model próprio evita duplicação de dados, deixa o código mais limpo, mais organizado e mais fácil.

ViniGodoy

Você já leu os artigos que eu te passei?

ViniGodoy

Olha só.

Suponha que vc tenha a classe:
public class TitulosDoMain {
    public double getValorOriginal();
    public void setValorOriginal(double valor);
    public double getValorAberto();
    public void setValorAberto(double valor);
}

Aqui não coloquei implementação. Mas suponha que esses gets e sets funcionam.

Aí vc cria o seu TableModel. Ele vai trabalhar diretamente com uma lista de TitulosDoMains. A mesma que vc obtém do seu ServerFacade.

Vamos supor que vc queira para coluna 0 o valor Original e para coluna 1 o valor aberto.

public class TitulosTableModel extends AbstractTableModel {
    private static final int COL_VALOR_ORIGINAL = 0;
    private static final int COL_VALOR_ABERTO = 1;

    private List<TitulosDoMain> valores;       

    public TitulosTableModel(List<TitulosDoMain> valores) {
          this.valores = new ArrayList<TitulosDoMain>(valores);
    }

    public int getRowCount() {
        //Quantas linhas tem sua tabela? Uma cada item da lista.
        return valores.size();
    }

    public int getColumnCount() {
        //Quantas colunas tem a tabela? Nesse exemplo, só 2.
        return 2;
    }

    public String getColumnName(int columnIndex) {
        //Qual é o nome das nossas colunas?
        if (column == COL_VALOR_ORIGINAL) return "Valor orig.";
        if (column == COL_VALOR_ABERTO) return "Valor aberto";
    }

    public Object getValueAt(int row, int column) {
        //Precisamos retornar o valor da coluna column e da linha row.
        TitulosDoMain titulo = valores.get(row);
        if (column == COL_VALOR_ORIGINAL) return titulo.getValorOriginal();
        else if (column == COL_VALOR_ABERTO) return titulo.getValorAberto();
    }

    public  void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        //Vamos alterar o valor da coluna columnIndex na linha rowIndex com o valor aValue passado no parâmetro.
        //Note que vc poderia alterar 2 campos ao invés de um só.
        if (column == COL_VALOR_ORIGINAL) titulo.setValorOriginal(Double.parseDouble(aValue.toString()));
        else if (column == COL_VALOR_ABERTO) titulo.setValorAberto(Double.parseDouble(aValue.toString()));
    }

    public  Class getColumnClass(int columnIndex) {
        //Qual a classe das nossas colunas? Nesse caso, é double.
        return Double.class;
    }
    
    boolean isCellEditable(int rowIndex, int columnIndex) {
        //Indicamos se a célula da rowIndex e da columnIndex é editável. Nossa tabela toda é.
        return true;
    }
}
Agora, para fazer sua tabela, faça só:
tableTitulos.setModel(new TitulosTableModel(ServerFacade.getInstance().findTITULOS(titulos)));

O ideal ainda seria adicionar métodos para inserir e remover títulos do seu modelo. Para isso, você terá que usar os eventos para avisar a tabela que isso ocorreu. Os eventos chamam-se fireTableRowInserted, fireTableRowRemove. Um exemplo:

public void addTitulo(TitulosDoMain titulo) {
    valores.add(titulo);
    //Informamos que a última linha foi adicionada.
    fireTableRowInserted(valores.size()-1, valores.size()-1);
}

O que vc tem que entender é que quem chama os métodos do model é a tabela. É a forma dela perguntar para o seu programa o que colocar em seu interior.
Ela diz "Estou desenhando a linha row e coluna col. Que valor tem aí?". Mas ela faz isso através do método getValueAt.

Da mesma forma, quando alguém edita sua tabela, ela diz:
"Ei! Editaram uma das células. É a de linha rowIndex e coluna columnIndex. O objeto, já com a modificação é esse aValue aqui.". Ela faz isso através do setValueAt. Então, vc atualiza o seu modelo, se achar que deve.

A regra é:
1. A tabela desenha dados, mas não sabe que dados são esses;
2. O modelo é quem sabe a respeito dos dados;

D

Bom dia pessoal.
–Até vi alguns tópicos criados aqui e em outros fóruns mas a solução para este problema não ficou clara.
Queria saber se vocês já conseguiram implementar uma alteração em uma célula X enquanto digita-se algo em determinada célula.
Preciso de algo parecido com este abaixo, porém para células de uma JTable:

keyReleased(KeyEvent kr) {
		if(kr.getSource() == textVlroriginal) {
			if(textVlroriginal.getText().length() > 0) {
				textVlrAberto.setText(textVlroriginal.getText()); // alterar o textVlraberto enquanto for digitado algo no textVlroriginal
			}
		}
	}

Sei que tem que implementar o TableModelListener e as ações devem ser no Model, e não na JTable, mas já quebrei a cabeça e não consegui. O máximo que consegui desta maneira foi mostrar uma msg dizendo que houve uma alteração na célula (TableModel.UPDATE), mas o valor é alterado para o que estava anteriormente após a msg. Tentei um setValueAt no evento do Model mas não consegue encontrar a linha/coluna que especifiquei e dá exceção.
Valeu!

D

Exceção de índice… vou colocar novamente o TableModelListener para ver exatamente o erro e posto. Você teria um exemplo para eu ver se estou fazendo da maneira correta ?
-Valeu pela atenção.

D
ViniGodoy:
diogoroos:
Exceção de índice... vou colocar novamente o TableModelListener para ver exatamente o erro e posto. Você teria um exemplo para eu ver se estou fazendo da maneira correta ? -Valeu pela atenção.

Como assim "exceção de índice". Você tem um model próprio?

A idéia é atualizar duas propriedades do seu objeto, ao invés de uma. Então é só fazer isso!
public class SampleTableModel extends AbstractTableModel

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    if (columnIndex == COL_VALOR_ORIGINAL) {
            valores.get(rowIndex).setValorOriginal((Double)value);
            valores.get(rowIndex).setValorAberto((Double)value);
    }
}

Valores seria um JList com sua classe, seja ela qual for.

Estou usando DefaultTableModel pq ainda não consegui criar um AbstractTableModel com JCheckBox...
-Obrigado pelo exemplo.

D
ViniGodoy:
Basta fazer:
public class SampleTableModel extends AbstractTableModel  {
  
   public void setValueAt(Object aValue, int rowIndex, int columnIndex) {   
       if (columnIndex == COL_VALOR_ORIGINAL) {   
               valores.get(rowIndex).setValorOriginal((Double)value);   
              valores.get(rowIndex).setValorAberto((Double)value);   
      }   
   }  

   public Class <?> getColumnClass(int columnIndex) {
       if (columnIndex == COL_CHECK) //Índice da coluna com checkbox
          return Boolean.class;
       return Object.class; //Demais colunas
    }
}

Obrigado Vinícius!

Desculpe a ignorância a respeito, estou tentando implenetar a classe com um modelo AbstractTableModel mas ainda não consegui. O que seria setValorOriginal ?

A forma que estou utilizando o DefaultTableModel é a seguinte:
public DefaultTableModel getModelEmpresas() {
		String[] titles = new String[] { "Selecionado", "VlrAberto", "VlrOriginal", "Resultado"};
		return new DefaultTableModel(new Object[][]{}, titles) {
			private static final long serialVersionUID = 1L;
			@SuppressWarnings("unchecked")
			Class[] types = new Class[] { java.lang.Boolean.class, java.lang.Object.class,
					java.lang.Object.class, java.lang.Object.class};
			boolean[] canEdit = new boolean[] { true, false, true, true};

			@SuppressWarnings("unchecked")
			public Class getColumnClass(int columnIndex) {
				return types[columnIndex];
			}
			public boolean isCellEditable(int rowIndex, int columnIndex) {
				return canEdit[columnIndex];
			}
		};
	}
E para popular a tabela eu faço:
TITULOSDOMAIN titulos = new TITULOSDOMAIN();
List<TITULOSDOMAIN> listagem = ServerFacade.getInstance().findTITULOS(titulos); //recebe a lista de titulos do banco
DefaultTableModel modelo = (DefaultTableModel)tableTitulos.getModel();
modelo.setRowCount(0);
for (TITULOSDOMAIN titulos: listagem) {
	modelo.addRow(mountRows(empresas)); //mountRows retorna um vector com as linhas preenchidas
}
tableTitulos.setModel(modelo);

Se não for pedir demais, como ficaria com AbstractTableModel ao invés de DefaultTableModel ?

Muito obrigado mais uma vez.

Criado 30 de julho de 2008
Ultima resposta 30 de jul. de 2008
Respostas 8
Participantes 2