Construindo uma JTable

19 respostas
MarujoRafao

Senhores, antes dem ais nada, eu ja procurei aqui n oforum, li muitos posts sobre editar celular e talz, mas não consegui fazer funcionar o que eu quero.

Eu tenho uma JTable com 15 colunas e N linhas. O que ue quero é que quando eu editar a Celula 5 da coluna 10 por exemplo, ao apertar Enter(confirmando a edição), eu consiga pegar o valor inserido e dar um setValueAt em todas as linhas da coluna 15 por exemplo.

Na verdade eu estuo cmo dificuldades em colocar o meu setValueAt no momento em que o usuario aperta o enter! Por favor, me ajudem.

Abraço

19 Respostas

ViniGodoy

Poste seu tableModel.

Mas vai ficar algo mais ou menos assim:

@Override public void setValueAt(Object value, int row, int column) { if (column == 5) { for (SuaClasse obj : lista) { obj.setValor((Integer)value); } fireTableDataChanged(); } }

MarujoRafao

Aqui vai o código aonde eu monto o jtable:

private void montaJanela(){ 
                 		
   		try{			
   			String SQL = "select i.ID, produto->codigo as cod, produto->descricao as produto, peso as peso, precocusto as precocusto, precogerencia as precogerencia, preco as preco, unidadepreco->mnemonico as unpreco, PrecoSimulado as precosimulado, precofrete as frete, precocorte as corte, precoembalagem as embalagem, '0' as Margem, '0' as desconto from coml.pedidoitem i, Coml.Pedido p";
            rs = MeuState.executeQuery(SQL);
            Colunas = new String []{"ID", "Cod.", "Produto", "Peso", "Preco Custo", "Preco Gerência", "Preco", "Un.", "Preco Simulado", "Corte", "Frete", "Embalagem","Margem", "Desconto"};
            Dados = new String [][]{};
           	DefaultTableModel modelo = new DefaultTableModel(Dados, Colunas);
           	table = new JTable();           	           	
            scroll = new JScrollPane(table);
            this.setContentPane(scroll);
           	table.setModel(modelo);           	

           	table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);  
           	table.getColumnModel().getColumn(2).setPreferredWidth(40);
           	table.getColumnModel().getColumn(2).setPreferredWidth(250);
        	table.getColumnModel().getColumn(3).setPreferredWidth(45);
        	table.getColumnModel().getColumn(7).setPreferredWidth(35);
           	table.getColumnModel().getColumn(9).setPreferredWidth(35); 
           	table.getColumnModel().getColumn(10).setPreferredWidth(35); 
           
           	while (rs.next()){           		
           		modelo.addRow( new String [] {rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6), rs.getString(7), rs.getString(8), rs.getString(9), rs.getString(10), rs.getString(11), rs.getString(12),rs.getString(13),rs.getString(14) } );
           	}
          
           	
   		}

   		catch(SQLException ex){
   			JOptionPane.showMessageDialog(null,"Erro ao executar query.", "Erro",0);
               ex.printStackTrace();
   		}   		
    }
MarujoRafao

Eu tentei fazer esse trecho do codigo que o vinicius colocou, mas nao entendi muito bem. Em que momento do código eu vou chamar esse public void setValueAt ?? E tb, o que eu colocou na linnha “for (SuaClasse obj : lista)” ??

Caramba, nao achei que fosse tao complicado fazer update em celulas de um jtable a partir de um valor inserido em outra celula O.o

ViniGodoy

É complicado se você usar o DefaultTableModel.

Ou seja, para você manipular um JTable, você precisa primeiro entender como o JTable funciona. Siga o link da minha assinatura e aprenda a fazer seu próprio TableModel, filho de AbstractTableModel.

Aí esse e vários outros problemas que você ainda não teve, serão facilmente resolvidos.

MarujoRafao

Beleza Vini, implementei um modelo aqui de um dos links que vc passou. Realmente parece ser bem mais fácil e organizado. Como eu faço agora para que ao atualizar uma celula, seja atualizado todas as celulas de uma outra coluna? tentei fazer do jeito la que vc sugeriu:

public void setValueAt(Object valor, int linha, int coluna) {
		
		MVCTabela celula = dados.get(linha);
		MVCTabela col = dados.get(coluna);
		
		switch (coluna) {
		case 0:
			celula.setCodigo(valor.toString()); // 
			break;
			
		case 1:
			celula.setProduto(valor.toString()); //
			break;
			
		case 2:
			celula.setPreco(valor.toString()); // 			
			break;
			
		case 3:
			celula.setMargem(valor.toString());	
		
			for (MVCTabela obj : lista) {  
				obj.setPreco((String)value);  
			} 
		}
		fireTableDataChanged();
	}

mas o que eu coloco na lista? E no caso, como eu conseguiria obter o numero total de linhas da minha tabela para eu fazer um loop para ir setando os valores em determinada coluna??

Obrigado mais uma vez

ViniGodoy

A lista é o seu “dados”.

ViniGodoy

Pode postar seu model completo?

O seu ArrayList de dados deveria ser com objetos da sua classe de negócios, não um array de colunas e de linhas.

MarujoRafao
public class MontaTabela extends AbstractTableModel {

	private static final long serialVersionUID = 1L;

	private List<MVCTabela> dados;

	public MontaTabela() {
		dados = new ArrayList<MVCTabela>();
	}

	public MontaTabela(List<MVCTabela> lista) {
		this();
		dados.addAll(lista);
	}


	@Override
	public Class<?> getColumnClass(int coluna) {
		return String.class;
	}

	@Override
	public int getColumnCount() {
		return 4;
	}

	@Override
	public String getColumnName(int coluna) {
		// vamos retornar o nome de cada coluna
		switch (coluna) {
		case 0:
			return "Cod."; // o nome da primeira coluna
		case 1:
			return "Produto"; // o nome da segunda
		case 2:
			return "Preço"; // e o da terceira
		case 3:
			return "Margem";
		default:
			return "";
		}
	}

	@Override
	public int getRowCount() {
		return dados.size();
	}

	@Override
	public Object getValueAt(int linha, int coluna) {
		MVCTabela c = dados.get(linha);
		switch (coluna) {
		case 0:
			return c.getCodigo(); 
		case 1:
			return c.getProduto();
		case 2:
			return c.getPreco(); 
		case 3:
			return c.getMargem();
		default:
			return null; // isso nunca deve ocorrer
		}
	}

	@Override
	public boolean isCellEditable(int rowIndex, int columnIndex) {
		
		return columnIndex != 0; 
	}

	@Override
	public void setValueAt(Object valor, int linha, int coluna) {
		MVCTabela celula = dados.get(linha);
		MVCTabela col = dados.get(coluna);
		
		switch (coluna) {
		case 0:
			celula.setCodigo(valor.toString()); // 
			break;
			
		case 1:
			celula.setProduto(valor.toString()); //
			break;
			
		case 2:
			celula.setPreco(valor.toString()); // 			
			break;
			
		case 3:
			celula.setMargem(valor.toString());			
			for (MVCTabela : dados) {  
				dados.get(i).setPreco(valor.toString());  
			}  
		}
		fireTableDataChanged();
	}

	public void remove(int indice) {
		dados.remove(indice);
		fireTableRowsDeleted(indice, indice);
	}

	public int getIndice(MVCTabela c) {
		return dados.indexOf(c);
	}

	public void adicionaLista(List<MVCTabela> lista) {
		int i = dados.size();
		dados.addAll(lista);
		fireTableRowsInserted(i, i + lista.size());
	}


	public void limpaLista() {
		int i = dados.size();
		dados.clear();
		fireTableRowsDeleted(0, i - 1);
	}
	
	public void ordenaLista() {      
	   
	     //Collections.sort(dados);  
	   
	}  

}

Minhas classes foram baseadas no exemplo do marcobiscaro2112 que consta no link da sua assinatura!

Obrigado pela atenção

ViniGodoy

Sua classe que contém Produto, Preço e Margem chama-se MVCTabela? Não deveria se chamar Produto?

MarujoRafao

É que eu coloquei esse nome pq aqui onde trabalho usamos linguagem ZEN pra desenvolver com banco de dados CACHE. E a estrutura que eles utilizam nos arquivos MVC é semelhante a esta classe que nomeiei MVCTabela. Acabei nomeando-a assim afim do povo aqui conseguir se achar caso um dia eu não esteja mais poraqui, pois ninguem conhece java, inclusive eu. O.o

Outra dúvida. Tenho o meu código pra alterar a cor de celular, linhas ou colunas. Eu fiz assim:

DefaultTableCellRenderer colorRenderer = new DefaultTableCellRenderer() {   
        public void setValue(Object value) {   
          setBackground(Color.GRAY);  
          setForeground(Color.WHITE);  
          super.setValue(value);   
        }  
   };

Agora, aonde eu colocaria ele? Eu tentei chamar no tableChanged ou na hora que cria a tabela, mas nada aconteceu! =/

Obrigado mais uma vez!

MarujoRafao

Eu tnetei agora colocar no tableChanged o código:

tabela.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {  
             public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {  
                 super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);  
                 if (row == 1) {  
                     setBackground(Color.LIGHT_GRAY);  
                 } else {  
                     setBackground(null);  
                 }  
                 return this;  
             }  
         });

Mas to tomando NPE

=/

MarujoRafao

Ainda estou com o erro. Alguém poderia me ajudar?

ViniGodoy

Esse código você coloca logo que constroi a tabela. Não no TableChanged.

Aliás, pq vc quer pintar a segunda linha da tabela de cinza?

MarujoRafao

Opa Viny, obrigado pela resposta.

Então, isso é só um teste cara. Eu nem sei que cores vão ser usadas ainda nas linhas, colunas e celulas. Estou apenas testando essa funcionalidade, entre outras aqui tb. :wink:

Então, eu tentei colocar no tableChanged esse codigo pq na verdade eu queria criar tipo uma função para que, por exemplo, qndo a celula X fosse alterada, eu pudesse chamar essa função para que a coluna Y mudasse de cor. Mas eu nao estou conseguindo =/

ViniGodoy

Não e assim que funciona. Sempre que um valor de uma célula é alterada, o table automaticamente chama o tableRenderer. Você não precisa registrar um evento para isso.

MarujoRafao

Blza cara, obrigado pelas informações.

Vc saberia me dizer se, caso eu queira fazer essa aplicação que eu fiz em swing rodar em uma applet, seria possível? Sem fazer grandes alterações é lógico.

Eu comecei a estudar applet agora, e pelo que eu vi, é um programa em java puro que roda numa página html.

Vlw, abraço

ViniGodoy

É fácil sim. Principalmente se você desenhar tudo dentro de um JPanel.

MarujoRafao

Cara, voltando as dúvidas sobre o JTable, ainda trabalhando com cores, tenho uma coluna na qual sua primeira linha será um valor SIM ou NAO. Se o usuário escrever SIM nela, entao a cor da coluna inteira ficará verde por exemplo. Se ele escrever NAO, ou qualquer outra coisa, a cor da coluna ficará vermelha. Pois bem, eu escrevi o metdoo defautTableRender no construtuor da minha tabela.

Mas está acontecendo o seguinte: Qndo eu carrega minha Jtable, ele verifica o valor da primeira linha da coluna X e se for SIM ele me retorna certinho a cor. O problema está em qndo ocorre algum evento na tabela. Qndo a tabela chama o tableRenderer, ele simplesmente trata o valor como se fosse NAO, e a cor fica amarela, mesmo o vlaor da celula sendo SIM. Aonde estou errando?

tabela.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){
			public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {				
				super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);    																		
				if(row == 0){					
					if(column == 21 || column == 22 || column == 23 || column == 24 || column == 25 || column == 26){						
						setBackground(Color.yellow);						
					}
					else{
						setBackground(new Color(238,238,238));
					}
				
				}else if(row == 1){
					
					if(column == 4 )
						setBackground(new Color(165,255,165));																					
					else if(column == 10 || column == 11 || column == 39 || column == 40 || column == 41)
						setBackground(new Color(165,255,165));
					
					else if(column == 21 || column == 22 || column == 23 || column == 24 || column == 25 || column == 26)						
						setBackground(Color.cyan);
					
					else
						setBackground(new Color(238,238,238));
												
/*
É AQUI QUE TRATA A COLUNA ONDE ESTOU TENDO O PROBLEMA OBSERVE QUE FAÇO A VERIFICAÇÃO SE O VALOR DA CELULA 1-4 É IGUAL A 'SIM'. O PROBLEMA ESTÁ QNDO ACONTECE ALGUM EVENTO NA TABELA. QNDO O TABLERENDERER É CHAMADO NOVAMENTE, ELE PARECE NÃO ENTENDER ESSA CONVERSAO PARA STRING QUE FAÇO.
                                                                 */
				}else if(column == 4){					
					System.out.println(table.getValueAt(1, 4));
							
					if((String) table.getValueAt(1, 4) == "SIM" || table.getValueAt(1, 4) == "SIM" || table.getValueAt(1, 4).toString() == "SIM")
						setBackground(Color.cyan);
					else
						setBackground(Color.pink);		



				}else if (column == 10){					
					setBackground(new Color(255,255,191));
					
				}else if (column == 11){					
					setBackground(new Color(204,255,204));
					
				}else if (column == 36) {    
			    	setBackground(new Color(255,255,191));   			    				   			    																
					
			    }else{			    	
			        setBackground(null);
			        
			    }
			      return this;  

			    }
			
			});
MarujoRafao

Ainda nao consegui resolver. Alguem tem alguma sugestão?

Criado 18 de outubro de 2010
Ultima resposta 8 de nov. de 2010
Respostas 19
Participantes 2