JTable com células JTextField

Ae galera,

Eu tenho um MyJTextField, um textfield personalizado que só aceita caracteres que representem números float…
O que eu preciso é criar uma JTable na qual cada célula da mesma seja esse MyJTextField, para que se comporte da maneira que programei o MyJTextField…

É possível? Como?

Talvez voce tenha que criar uma cell render personalizada para a jtable da uma pesquisa na net mas acredito que a resposta seje essa mesmo.

tem q também criar um cell editor, no entanto se por acaso você estiver utilizando um tablemodel criado por você, se você colocou os dados da coluna como float então automaticamente a edição só vai permitir valores desse tipo.
fica até em vermelho a borda da célula quando se coloca um valor inválido

Podem me dar um exemplo ou me fornecer o TableModel caso haja algum espalhado por aí?
Estou usando o DefaultTableModel (eu sei que não devo, mas estou).

dá uma olhada ae

http://staticjava.blogspot.com/

Tem diversos exemplos de TableModel ao lado do link em vermelho da minha assinatura.

A partir do momento que você precisa de coisas mais específicas, como essa, o DefaultTableModel deixa de ser uma boa opção.

Outra coisa, por que vc não usou só um InputValidator ou um Document personalizado, ao invés de criar um filho para o JTextField inteiro?

Ótimo, vou tentar criar uma model pra mim, obrigado!

… mas a minha dúvida persiste. Eu não sei como fazer para permitir só entrada de números float em uma JTable!

Você vai:
a) Criar a classe FloatCellEditor, que implementa TableCellEditor e que retornará o seu MyTextField:
http://www.exampledepot.com/egs/javax.swing.table/CustEdit.html

b) Fazer seu TableModel retornar Float.class na coluna que é do tipo float;

c) Chamar o método model.setDefaultEditor(Float.class, new FloatCellEditor());

Pronto. O seu editor será usado no lugar do editor padrão do JTable.

[quote=ViniGodoy]Você vai:
a) Criar a classe FloatCellEditor, que implementa TableCellEditor e que retornará o seu MyTextField:
http://www.exampledepot.com/egs/javax.swing.table/CustEdit.html

b) Fazer seu TableModel retornar Float.class na coluna que é do tipo float;

c) Chamar o método model.setDefaultEditor(Float.class, new FloatCellEditor());

Pronto. O seu editor será usado no lugar do editor padrão do JTable.
[/quote]

Achei isso: http://grepcode.com/file/repo1.maven.org/maven2/org.softsmithy.lib/lib-core/0.1/org/softsmithy/lib/swing/FloatCellEditor.java#FloatCellEditor
importei o .jar
criei a classe como ele pediu
fiz setCellEditor(MyFloatCellEditor());

… e nada funcionou… to quase desistindo =S

Você seguiu todos os passos que falei?

Bom, eu até consegui que, ao entrar com algo que não fosse Double o campo ficasse vermelho e tal… só que quando eu digito números e dou enter, o número não fica na célula. Seguem as classes:

////////////////////////////////////////////////////////// CELLEDITOR

public class MyTableDoubleCellEditor  extends AbstractCellEditor implements TableCellEditor{
	 // This is the component that will handle the editing of the cell value
    private JComponent component = new MyTextFieldDouble(3,3);
    
	// This method is called when editing is completed.
    // It must return the new value to be stored in the cell.
	@Override
	public Object getCellEditorValue() {
		return ((JTextField)component).getText();
	}

	@Override
	public Component getTableCellEditorComponent(JTable table, Object value,
			boolean isSelected, int row, int column) {
		 // 'value' is value contained in the cell located at (rowIndex, vColIndex)

        if (isSelected) {
            // cell (and perhaps other cells) are selected
        }

        // Configure the component with the specified value
        ((MyTextFieldDouble)component).setText((String)value);

        // Return the configured component
        return component;
	}

}

////////////////////////////////////////////////////////// TABLE MODEL


public class MyValRefTableModel extends AbstractTableModel {
	
	private static final long serialVersionUID = 1L;

	/* Lista de Vetores de Strings que representam as linhas. */
	private List<String[]> linhas;

	/* Array de Strings com o nome das colunas. */
	private String[] colunas = new String[] {
			"Idade/Sexo", "CE (M\u00EDn.)", "CE (Máx.)", "Hb (M\u00EDn.)", "Hb (Máx.)", "Htc (M\u00EDn.)", 
			"Htc (Máx.)", "VCM (M\u00EDn.)", "VCM (Máx.)", "HCM (M\u00EDn.)", "HCM (Máx.)", 
			"CHCM (M\u00EDn.)", "CHCM (Máx.)"
	};



	/* CONSTRUTOR */
	public MyValRefTableModel() {
		linhas = new ArrayList<String[]>();
	}

	/* Retorna a quantidade de colunas. */
	@Override
	public int getColumnCount() {
		// Está retornando o tamanho do array "colunas".
		return colunas.length;
	}

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


	@Override
	public String getColumnName(int columnIndex) {
		// Retorna o conteúdo do Array que possui o nome das colunas
		return colunas[columnIndex];
	}

	;

	@Override
	public Class<?> getColumnClass(int columnIndex) {
	if(columnIndex > 0)
		return Double.class;
	else
		return String.class;
	};


	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		String[] dados = 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ãoas mesmas
		// que foram especificadas no array "colunas".
		switch (columnIndex) {

		// Seguindo o exemplo: "Tipo","Data de Cadastro", "Nome", "Idade"};
		case 0:
			return dados[0];
		case 1:
			return dados[1];
		case 2:
			return dados[2];
		case 3:
			return dados[3];
		case 4:
			return dados[4];
		case 5:
			return dados[5];
		case 6:
			return dados[6];
		case 7:
			return dados[7];
		case 8:
			return dados[8];
		case 9:
			return dados[9];
		case 10:
			return dados[10];
		case 11:
			return dados[11];
		case 12:
			return dados[12];
		default:
			// Isto não deveria acontecer...
			throw new IndexOutOfBoundsException("columnIndex out of bounds");
		}
	}

	//modifica na linha especificada
	public void setValueAt(String[] aValue, int rowIndex) {
		String[] dados = linhas.get(rowIndex); // Carrega o item da linha que deve ser modificado

		dados[0] = aValue[0];
		dados[1] = aValue[1];
		dados[2] = aValue[2];
		dados[3] = aValue[3];
		dados[4] = aValue[4];
		dados[5] = aValue[5];
		dados[6] = aValue[6];
		dados[7] = aValue[7];
		dados[8] = aValue[8];
		dados[9] = aValue[9];
		dados[10] = aValue[10];
		dados[11] = aValue[11];
		dados[12] = aValue[12];

		fireTableCellUpdated(rowIndex, 0);
		fireTableCellUpdated(rowIndex, 1);
		fireTableCellUpdated(rowIndex, 2);
		fireTableCellUpdated(rowIndex, 3);
		fireTableCellUpdated(rowIndex, 4);
		fireTableCellUpdated(rowIndex, 5);
		fireTableCellUpdated(rowIndex, 6);
		fireTableCellUpdated(rowIndex, 7);
		fireTableCellUpdated(rowIndex, 8);
		fireTableCellUpdated(rowIndex, 9);
		fireTableCellUpdated(rowIndex, 10);
		fireTableCellUpdated(rowIndex, 11);
		fireTableCellUpdated(rowIndex, 12);
	};


	@Override
	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return false;
	}


	public String[] getDados(int indiceLinha) {
		return linhas.get(indiceLinha);
	}



	/* Adiciona um registro. */
	public void addDados(String[] m) {
		// Adiciona o registro.
		linhas.add(m);


		int ultimoIndice = getRowCount() - 1;

		fireTableRowsInserted(ultimoIndice, ultimoIndice);
	}

	/* Remove a linha especificada. */
	public void removeDados(int indiceLinha) {
		linhas.remove(indiceLinha);

		fireTableRowsDeleted(indiceLinha, indiceLinha);
	}

	/* Adiciona uma lista de Vetores de Strings ao final dos registros. */
	public void addListaDeDados(List<String[]> dados) {
		// Pega o tamanho antigo da tabela.
		int tamanhoAntigo = getRowCount();

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

		fireTableRowsInserted(tamanhoAntigo, getRowCount() - 1);
	}

	/* Remove todos os registros. */
	public void limpar() {
		linhas.clear();


		fireTableDataChanged();
	}

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



}

////////////////////////////////////////////////////////// COMO ESTOU COLOCANDO NA TABELA

		MyValRefTableModel modelo = new MyValRefTableModel();
		modelo.addDados(new String[]{"Nascimento (cordão)", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"1 a 3 dias", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"1 semana", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"2 semanas", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"1 mês", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"3 a 6 meses", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"6 meses a 2 anos", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"2 a 6 anos", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"6 a 12 anos", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"(F) entre 12 e 18 anos", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"(M) entre 12 e 18 anos", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"(F) entre 18 e 49 anos", "","","","","","","","","","","",""});
		modelo.addDados(new String[]{"(M) entre 18 e 49 anos", "","","","","","","","","","","",""});
		
		tabela.setCellEditor(new MyTableDoubleCellEditor());
		tabela.setModel(modelo);

O método que vc deve chamar na tabela é:

Além disso, seria mais fácil trabalhar com Doubles diretamente dentro do model, ao invés de Strings. Mas não é isso que está impedindo seu código de funcionar.

A razão pela qual o número não fica na célula é que a implementação do seu método setValueAt está completamente errada. Para começar, nem a assinatura do método é válida, portanto, nem sequer uma sobreposição você está fazendo. O java encara o que você fez como um segundo método, que a JTable nunca vai chamar.

O método setValueAt te informa que um dado foi atualizado. O parâmetro aValue é exatamente o dado que seu editor retornou.
Seu papel, dentro desse método, é atualizar seu model para fazer a atualização desse dado, ou negá-la.

O correto seria você fazer assim:

public void void setValueAt(Object aValue, int rowIndex, int columnIndex) { String[] dados = linhas.get(rowIndex); // Carrega o item da linha que deve ser modificado dados[columnIndex] = aValue.toString(); };

Note que não é necessário disparar um evento dizendo que a célula foi atualizada aqui.
Como se trata de uma edição, o JTable já sabe disso.

Sugiro que você perca um tempo, leia sobre TableModel, e estude os exemplos ligados ao link da minha assinatura. Procure modelar corretamente classes de negócio, e deixar um List do seu objeto dentro do model. Procure entender cada um dos métodos que a interface TableModel declara, leia os javadocs:
http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/table/TableModel.html

Sua vida com o JTable vai ficar muitíssimo mais fácil ao entender como cada componente dentro da tabela funciona.