[RESOLVIDO] Problemas ao selecionar linha com data na JTable (não é defaulttablemodel)

Pessoal, em minha TableModel, a data aparece corretamente no formato dd/MM/yyyy, mas com o método de exibir o conteúdo da linha selecionada em um JTextField, a data 20/05/2011, por exemplo, aparece no JTextField como 1305860400000.
O código da minha tablemodel:

package tabelas;


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

/**
 * Implementação de Table Model para exibir os Sócios.
 * 
 * @author Eric Yuzo
 */
public class SocioTableModel extends AbstractTableModel {

	/* Lista de Sócios que representam as linhas. */
	private List<Socio> linhas;

	/* Array de Strings com o nome das colunas. */
	private String[] colunas = new String[] {
			"Nome", "Telefone", "Data de Cadastro", "Mensalidade"};


	/* Cria um SocioTableModel vazio. */
	public SocioTableModel() {
		linhas = new ArrayList<Socio>();
	}

	/* Cria um SocioTableModel carregado com
	 * a lista de sócios especificada. */
	public SocioTableModel(List<Socio> listaDeSocios) {
		linhas = new ArrayList<Socio>(listaDeSocios);
	}


	/* Retorna a quantidade de colunas. */
	@Override
	public int getColumnCount() {
		// Está retornando o tamanho do array "colunas".
		// Mas como o array é fixo, vai sempre retornar 4.
		return colunas.length;
	}

	/* Retorna a quantidade de linhas. */
	@Override
	public int getRowCount() {
		// Retorna o tamanho da lista de sócios.
		return linhas.size();
	}

	/* Retorna o nome da coluna no índice especificado.
	 * Este método é usado pela JTable para saber o texto do cabeçalho. */
	@Override
	public String getColumnName(int columnIndex) {
		// Retorna o conteúdo do Array que possui o nome das colunas
		// no índice especificado.
		return colunas[columnIndex];
	};

	/* Retorna a classe dos elementos da coluna especificada.
	 * Este método é usado pela JTable na hora de definir o editor da célula. */
	@Override
	public Class<?> getColumnClass(int columnIndex) {
		// Retorna a classe referente a coluna especificada.
		// Aqui é feito um switch para verificar qual é a coluna
		// e retornar o tipo adequado. As colunas são as mesmas
		// que foram especificadas no array "colunas".
		switch (columnIndex) {
		case 0: // Primeira coluna é o nome, que é uma String.
			return String.class;
		case 1: // Segunda coluna é o telefone, que também é uma String..
			return String.class;
		case 2: // Terceira coluna é a data de cadastro,
				// apesar de ser do tipo Calendar,
				// estou retornando Date por causa da formatação.
			return Date.class;
		case 3: // Quarta coluna é a mensalidade, um double.
			return Double.class;
		default:
			// Se o índice da coluna não for válido, lança um
			// IndexOutOfBoundsException (Exceção de índice fora dos limites).
			// Não foi necessário verificar se o índice da linha é inválido,
			// pois o próprio ArrayList lança a exceção caso seja inválido.
			throw new IndexOutOfBoundsException("columnIndex out of bounds");
		}
	}

	/* Retorna o valor da célula especificada
	 * pelos índices da linha e da coluna. */
	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		// Pega o sócio da linha especificada.
		Socio socio = linhas.get(rowIndex);

		// Retorna o campo referente a coluna especificada.
		// Aqui é feito um switch para verificar qual é a coluna
		// e retornar o campo adequado. As colunas são as mesmas
		// que foram especificadas no array "colunas".
		switch (columnIndex) {
		case 0: // Primeira coluna é o nome.
			return socio.getNome();
		case 1: // Segunda coluna é o telefone.
			return socio.getTelefone();
		case 2: // Terceira coluna é a data de cadastro.
			return socio.getDataDeCadastro().getTime();
		case 3: // Quarta coluna é a mensalidade.
			return socio.getMensalidade();
		default:
			// Se o índice da coluna não for válido, lança um
			// IndexOutOfBoundsException (Exceção de índice fora dos limites).
			// Não foi necessário verificar se o índice da linha é inválido,
			// pois o próprio ArrayList lança a exceção caso seja inválido.
			throw new IndexOutOfBoundsException("columnIndex out of bounds");
		}
	}

	/* Seta o valor da célula especificada
	 * pelos índices da linha e da coluna.
	 * Aqui ele está implementado para não fazer nada,
	 * até porque este table model não é editável. */
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {};

	/* Retorna um valor booleano que define se a célula em questão
	 * pode ser editada ou não.
	 * Este método é utilizado pela JTable na hora de definir o editor da célula.
	 * Neste caso, estará sempre retornando false, não permitindo que nenhuma
	 * célula seja editada. */
	@Override
	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return false;
	}


	////////////////////////////////////////////////////////////
	// Os métodos declarados até aqui foram as implementações //
	// de TableModel, que são continuamente utilizados        //
	// pela JTable para definir seu comportamento,            //
	// por isso o nome Table Model (Modelo da Tabela).        //
	//                                                        //
	// A partir de agora, os métodos criados serão            //
	// particulares desta classe. Eles serão úteis            //
	// em algumas situações.                                  //
	////////////////////////////////////////////////////////////


	/* Retorna o sócio da linha especificada. */
	public Socio getSocio(int indiceLinha) {
		return linhas.get(indiceLinha);
	}
	
	/* Adiciona um registro. */
	public void addSocio(Socio socio) {
		// Adiciona o registro.
		linhas.add(socio);

		// Pega a quantidade de registros e subtrai um para achar
		// o último índice. É preciso subtrair um, pois os índices
		// começam pelo zero.
		int ultimoIndice = getRowCount() - 1;

		// Reporta a mudança. O JTable recebe a notificação
		// e se redesenha permitindo que visualizemos a atualização.
		fireTableRowsInserted(ultimoIndice, ultimoIndice);
	}

	/* Remove a linha especificada. */
	public void removeSocio(int indiceLinha) {
		// Remove o sócio da linha especificada.    	
		linhas.remove(indiceLinha);

		// Reporta a mudança. O JTable recebe a notificação
		// e se redesenha permitindo que visualizemos a atualização.
		fireTableRowsDeleted(indiceLinha, indiceLinha);
	}

	/* Adiciona uma lista de sócios ao final dos registros. */
	public void addListaDeSocios(List<Socio> socios) {
		// Pega o tamanho antigo da tabela.
		int tamanhoAntigo = getRowCount();

		// Adiciona os registros.
		linhas.addAll(socios);

		// Reporta a mudança. O JTable recebe a notificação
		// e se redesenha permitindo que visualizemos a atualização.
		fireTableRowsInserted(tamanhoAntigo, getRowCount() - 1);
	}

	/* Remove todos os registros. */
	public void limpar() {
		// Remove todos os elementos da lista de sócios.
		linhas.clear();

		// Reporta a mudança. O JTable recebe a notificação
		// e se redesenha permitindo que visualizemos a atualização.
		fireTableDataChanged();
	}

	/* Verifica se este table model está vazio. */
	public boolean isEmpty() {
		return linhas.isEmpty();
	}

}

E o método para exibir o conteúdo no JTextField:

private void linhaSelecionada(JTable tabela) {
        if (tabela.getSelectedRow() != -1) {
            tfNome2.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(),0).toString());
            tfTelefone2.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(),1).toString());
            tfData2.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(),2).toString());
            tfMensalidade.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(),3).toString());
        }
    }

Como corrigir? Obrigado pela ajuda!

Marky?
:shock:
ViniGodoy?
:frowning:
Alguém?
:?:
Me salvem, por favor
:frowning:

Bom dia Marcusluiz83.

Quando voce invoca o método “toString()” da data lá na linhaSelecionada, a data é convertida em string no seu formato original, ou seja em milliseconds, assim sendo, a converter para String voce deve mascarar a data com a classe SimpleDateFormat, desta forma:


private void linhaSelecionada(JTable tabela) {
        SimpleDateFormat formatdate = new SimpleDateFormat("dd/MM/yyyy");  
        if (tabela.getSelectedRow() != -1) {  
            tfNome2.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(),0).toString());  
            tfTelefone2.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(),1).toString());  
            tfData2.setText(formatdate.format(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(),2).toString()));  
            tfMensalidade.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(),3).toString());  
        }  
}

Uma outra dica que de dou é, vamos enxugar um pouco esse código, ou seja, ao invés de passar a tabela como parâmetro do método linhaSelecionada, porque não passar já a linha selecionada, e pegar o objeto Socio do seu tablemodel, atráves do método getSocio();


private void linhaSelecionada(int linha) {
        SimpleDateFormat formatdate = new SimpleDateFormat("dd/MM/yyyy"); 
        if (linha != -1) {
            Socio socio = tbSocios.getModel().getSocio(linha);   
            tfNome2.setText(socio.getNome());  
            tfTelefone2.setText(socio.getTelefone());  
            tfData2.setText(formatdate.format(socio.getDataDeCadastro()));  
            tfMensalidade.setText(socio.getMensalidade());  
        }  
} 

Jorge da Silva Abreu

Siga a dica do discorpio.

O ideal é que, apenas o JTable chame diretamente os métodos setValueAt e getValueAt.

Na tela, trabalhe com o getSocio(), foi para isso que você o criou. :slight_smile:

Amigos, boa tarde e obrigado pelas dicas.

Este é o primeiro teste que estou fazendo criando a própria tablemodel. Peguei este código aqui no GUJ, e tô conseguindo exibir na JTable o conteúdo de meu banco de dados. Sempre usei DefaultTableModel, e na propriedade de minha tabela, utilizava o seguinte código para chamar o método linhaSelecionada():

tbSocios.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lsmSocios = tbSocios.getSelectionModel();
lsmSocios.addListSelectionListener(new ListSelectionListener(){
		public void valueChanged(ListSelectionEvent e){
			if(! e.getValueIsAdjusting()){
				linhaSelecionada(tbSocios);
			}
		}
});

Ao tentar a segunda dica do Jorge, que seria a mais apropriada, esbarrei nos problemas:

private void linhaSelecionada(int linha) {
        SimpleDateFormat formatdate = new SimpleDateFormat("dd/MM/yyyy");        
        if (linha != -1) {
            Socio socio = tbSocios.getModel().getSocio(linha);            
            tfNome2.setText(socio.getNome());            
            tfTelefone2.setText(socio.getTelefone());            
            tfData2.setText(formatdate.format(socio.getDataDeCadastro()));
            //tfMensalidade.setText(socio.getMensalidade());  
        }        
    }  
  1. O método linhaSelecionada(int linha) não é usado. Neste caso, sinceramente, não sei como chama-lo.
  2. cannot find symbol
    symbol: method getSocio(int)
    location: interface javax.swing.table.TableModel

E quando tentei a primeira dica:

private void linhaSelecionada(JTable tabela) {
        SimpleDateFormat formatdate = new SimpleDateFormat("dd/MM/yyyy");        
        if (tabela.getSelectedRow() != -1) {            
            tfNome2.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(), 0).toString());            
            tfTelefone2.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(), 1).toString());            
            tfData2.setText(formatdate.format(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(), 2).toString()));            
            tfMensalidade.setText(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(), 3).toString());            
        }        
    }

O erro foi:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Cannot format given Object as a Date
        at java.text.DateFormat.format(DateFormat.java:281)
        at java.text.Format.format(Format.java:140)
        at tabelas.NewJFrame.linhaSelecionada(NewJFrame.java:248)
        at tabelas.NewJFrame.access$100(NewJFrame.java:31)
        at tabelas.NewJFrame$1.valueChanged(NewJFrame.java:70)
        at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:167)
        at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:137)
        at javax.swing.DefaultListSelectionModel.setValueIsAdjusting(DefaultListSelectionModel.java:668)
        at javax.swing.plaf.basic.BasicTableUI$Handler.setValueIsAdjusting(BasicTableUI.java:923)
        at javax.swing.plaf.basic.BasicTableUI$Handler.mouseReleased(BasicTableUI.java:1136)
        at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:273)
        at java.awt.Component.processMouseEvent(Component.java:6289)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
        at java.awt.Component.processEvent(Component.java:6054)
        at java.awt.Container.processEvent(Container.java:2041)
        at java.awt.Component.dispatchEventImpl(Component.java:4652)
        at java.awt.Container.dispatchEventImpl(Container.java:2099)
        at java.awt.Component.dispatchEvent(Component.java:4482)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4577)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
        at java.awt.Container.dispatchEventImpl(Container.java:2085)
        at java.awt.Window.dispatchEventImpl(Window.java:2478)
        at java.awt.Component.dispatchEvent(Component.java:4482)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:644)
        at java.awt.EventQueue.access$000(EventQueue.java:85)
        at java.awt.EventQueue$1.run(EventQueue.java:603)
        at java.awt.EventQueue$1.run(EventQueue.java:601)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
        at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
        at java.awt.EventQueue$2.run(EventQueue.java:617)
        at java.awt.EventQueue$2.run(EventQueue.java:615)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:614)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Poderiam me ajudar novamente, por favor?

Obrigado pela ajuda!

Boa noite a todos.

O problema é que voce está passando o parâmetro errado. No post anterior eu disse para voce trocar o parâmetro direto para a linha selecionada, assim sendo, você tem que passar a linha do tbSocios e não o tbSocios, então o código correto fica assim:


tbSocios.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);  
lsmSocios = tbSocios.getSelectionModel();  
lsmSocios.addListSelectionListener(new ListSelectionListener(){  
        public void valueChanged(ListSelectionEvent e){  
            if(! e.getValueIsAdjusting()){  
                linhaSelecionada(tbSocios.getSelectedRow());  // Passe a linha selecionado como parâmetro
            }  
        }  
});

Mesmo assim, se voce insiste em passar o JTable como parâmetro, nada te impede fazer isto, porém seguindo a dica do Vini Godoy, para quê voce criar uma TableModel com métodos getSocio(int row), se voce não usá-lo :?: Neste caso vamos ver o código passando o JTable como parâmetro:


// Passando o parâmetro com JTable
tbSocios.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);  
lsmSocios = tbSocios.getSelectionModel();  
lsmSocios.addListSelectionListener(new ListSelectionListener(){  
        public void valueChanged(ListSelectionEvent e){  
            if(! e.getValueIsAdjusting()){  
                linhaSelecionada(tbSocios);  
            }  
        }  
});

  
// Recebe o parâmetro como JTable
private void linhaSelecionada(JTable table) {  
        SimpleDateFormat formatdate = new SimpleDateFormat("dd/MM/yyyy");          
        if (table.getSelectedRow() != -1) {  
            Socio socio = table.getModel().getSocio(table.getSelectedRow());              
            tfNome2.setText(socio.getNome());              
            tfTelefone2.setText(socio.getTelefone());              
            tfData2.setText(formatdate.format(socio.getDataDeCadastro()));  
            tfMensalidade.setText(socio.getMensalidade());    
        }          
}

A formatação de SimpleDateFormat deu erro simplesmente que voce está convertendo um dado do tipo data para string antes com o método "toString(), e SimpleDateFormat só aceita um dado do tipo Date, neste código abaixo:


tfData2.setText(formatdate.format(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(), 2).toString())); 

// Retire o toString
tfData2.setText(formatdate.format(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(), 2)));

Contudo se voce reparar nos dois primeiros códigos, veja que não mudou muita coisa, apenas ressaltando em sempre utilizar o método getSocio(int row) que voce definiu dentro do seu TableModel, afinal como disse o Vini Godoy, implementar um método sem utilizá-lo é disperdício de recurso.

Um abraço.
Jorge da Silva Abreu

Jorge,

Muito obrigado pela ajuda e boa vontade! Consegui com a primeira dica que você me deu, cujo erro era:

fData2.setText(formatdate.format(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(), 2).toString()));   
  
// Retire o toString  
tfData2.setText(formatdate.format(tbSocios.getModel().getValueAt(tbSocios.getSelectedRow(), 2)));

Não entendo por que não consigo utilizando o método getSocio(int row) com a linha como parâmetro. Me dá o erro:

cannot find symbol
  symbol:   method getSocio(int)
  location: interface javax.swing.table.TableModel

Por este motivo, não consegui utilizar o método desperdiçado.

Muito obrigado e grande abraço!

É porque o
tbSocios.getModel()

Retorna a interface TableModel. Para utilizar o método, faça o cast:

SocioTableModel model = (SocioTableModel)tbSocios.getModel(); Socio socio = model.getSocio(linhaSelecionada);

Como esse cast acaba sendo muito utilizado, eu geralmente crio um método chamado getModel(), que já o faz:

public SocioTableModel getModel() { return (SocioTableModel) tbSocios.getModel(); }

Não use o getValueAt. Ele não é apropriado.

Como você fornece muitas vezes para o JTable dados formatados na forma de String, esse método irá retornar o dado com essa formatação.
E, geralmente, é mais simples e correto trabalhar com dados na sua forma original.

Bom dia, Vini!

Entendi o motivo do erro com a sua explicação, mas não está dando certo, acredito que seja por causa de eu ter inserido a JTable como componente pronto do Netbeans. Estou tendo problemas, por exemplo com o getColumModel(), pois a tabela do Netbeans já vem com a formatação padrão para as colunas.

De qualquer forma, fiquei feliz em conseguir implementar meu próprio TableModel. Como disse, esta tabela que você e o Jorge me ajudaram a solucionar, eu peguei aqui no GUJ, e fui além do exemplo exibindo os registros do banco de dados, e a exibição da linha selecionada nos JTextFields. Inclusive, já tirei as DefaulTableModel de um pequeno projeto que tenho, e funcionou. Nunca imaginei que fosse conseguir mostrar a data em minhas tabelas no formato dd/MM/yyyy porque tinha preguiça de abandonar a DefaultTableModel :smiley: .

Agradeço pela colaboração, e a partir de agora, vou estudar mais à fundo os componentes para não ser mais dependente do Netbeans.

Grande abraço!

Boa tarde a todos.

Me desculpem pessoal, eu esqueci de fazer o casting.

Seguindo a dica do Vini Godoy, faça o seguinte:

Crie o método getModel para não ficar fazendo casting a toda hora e depois construa o seu método linhaSelecionada assim:


// Criando método getModel()
public SocioTableModel getModel() {  
   return (SocioTableModel) tbSocios.getModel();  
}

// Passando o parâmetro
tbSocios.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);    
lsmSocios = tbSocios.getSelectionModel();    
lsmSocios.addListSelectionListener(new ListSelectionListener(){    
        public void valueChanged(ListSelectionEvent e){    
            if(! e.getValueIsAdjusting()){    
                linhaSelecionada(tbSocios.getSelectedRow());  // Passe a linha selecionada como parâmetro  
            }    
        }    
});  
  
// Recebe o parâmetro
private void linhaSelecionada(int linha) {  
        SimpleDateFormat formatdate = new SimpleDateFormat("dd/MM/yyyy");   
        if (linha != -1) {  
            Socio socio = getModel().getSocio(linha); // Utilizando o método getModel() criado por voce
            tfNome2.setText(socio.getNome());    
            tfTelefone2.setText(socio.getTelefone());    
            tfData2.setText(formatdate.format(socio.getDataDeCadastro()));    
            tfMensalidade.setText(socio.getMensalidade());    
        }    
}

A única diferença agora que voce quiser utilizar os métodos da sua TableModel, vai passar a utilizar o método getModel() criado por voce, que já fará o casting toda vez que voce precisar utilizá-lo.

Testa ai e vê se não dá certo agora.

Um abraço.

Jorge da Silva Abreu