Problema JTable StackOverflowError

2 respostas
casconi

Olá,

tenho aqui uma grande dor de cabeça.

Tenho duas tabelas. A segunda tabela depende de valores da primeira.

Tabela 1:
Quando altero uma célula nesta tabela, ele vai recalcular as outras mediante certas formulas, inclusive as da tabela 2.

Tabela 2:
Quando altero uma célula nesta, recalcula apenas nesta tabela.

Método de alteração:
Altera célula a célula, da esquerda para direita e depois começa a descer linhas, isto porque existem células que precisam de valores das anteriores.

Mas o meu problema não é esta modificação, a real dor de cabeça é eu ter o método que cada vez que altero uma célula ele activa aquele actionListener (ai a dor de cabeça), logo sempre que tento modificar, fica no loop constante para a primeira modificação.

MAIN
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TabMain extends JFrame {


	private static final long serialVersionUID = 1L;

	/* Main */
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				TabMain thisClass = new TabMain();
				thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				thisClass.add(new Tab().returnP(),BorderLayout.CENTER);
				thisClass.setLocationRelativeTo(null);
				thisClass.setResizable(false);
				thisClass.setMinimumSize(new Dimension(600, 330));
				thisClass.setVisible(true);
				thisClass.pack();
			}
		});
	}

	/* Construtor principal */
	public TabMain() {
		super();
		initialize();
	}

	/* Frame */
	private void initialize() {
		this.setSize(600, 330);
		this.setTitle("Teste");
	}

}
CODIGO
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

import java.awt.Rectangle;
import javax.swing.JTextField;
import javax.swing.JLabel;

public class Tab{

	private JPanel tab = null;
	private JScrollPane tab1SCR = null;
	private JTable tab1Tb = null;
	private DefaultTableModel modelTab1 = null;
	private JScrollPane tab2SCR = null;
	private JTable tab2Tb = null;
	private DefaultTableModel modelTab2 = null;
	private JTextField somaTf = null;
	private JLabel somaLB = null;

	/**
	 * This is the default constructor
	 */
	public Tab() {
		somaLB = new JLabel();
		somaLB.setBounds(new Rectangle(390, 263, 42, 25));
		somaLB.setText("Soma");
		tab = new JPanel();
		tab.setSize(600, 300);
		tab.setLayout(null);
		tab.add(getTab1SCR(), null);
		tab.add(getTab2SCR(), null);
		tab.add(getSomaTf(), null);
		tab.add(somaLB, null);
	}

	//Scrool da Tabela 1
	private JScrollPane getTab1SCR() {
		if (tab1SCR == null) {
			tab1SCR = new JScrollPane();
			tab1SCR.setBounds(new Rectangle(55, 10, 455, 120));
			tab1SCR.setViewportView(getTab1Tb());
		}
		return tab1SCR;
	}
	
	/**
	 * Tabela 1
	 */
	private JTable getTab1Tb() {
		if (tab1Tb == null) {
			String [] col = {"Col 1" , "Col 2", "Col 3"};
			Object [][] data = {{"1","2","3"},{"11","22","33"},{"111","222","333"}
			,{"1111","2222","3333"},{"11111","22222","33333"},{"111111","222222","333333"}};
			modelTab1 = new DefaultTableModel(data, col);
			tab1Tb = new JTable(modelTab1);
			tab1Tb.setCellSelectionEnabled(true);
			/**
			 * Captura de alterações
			 */
			tab1Tb.getModel().addTableModelListener(
					new TableModelListener() {
						public void tableChanged(TableModelEvent e) {
							System.out.println(e.getSource());
							alteracoes(1);
						}
					});
		}
		return tab1Tb;
	}
	
	//Scrool da Tabela 2
	private JScrollPane getTab2SCR() {
		if (tab2SCR == null) {
			tab2SCR = new JScrollPane();
			tab2SCR.setBounds(new Rectangle(55, 135, 455, 126));
			tab2SCR.setViewportView(getTab2Tb());
		}
		return tab2SCR;
	}

	/**
	 * Tabela 2
	 */
	private JTable getTab2Tb() {
		if (tab2Tb == null) {
			String [] col = {"Col 1" , "Col 2", "Col 3"};
			Object [][] data = {{"1","2","3"},{"11","22","33"},{"111","222","333"}
			,{"1111","2222","3333"},{"11111","22222","33333"},{"111111","222222","333333"}};
			modelTab2 = new DefaultTableModel(data, col);
			tab2Tb = new JTable(modelTab2);
			tab2Tb.setCellSelectionEnabled(true);
			/**
			 * Captura de alterações
			 */
			tab2Tb.getModel().addTableModelListener(
					new TableModelListener() {
						public void tableChanged(TableModelEvent e) {
							System.out.println(e.getSource());
							alteracoes(2);
						}
					});
		}
		return tab2Tb;
	}
	
	/**
	 * Efectua accao mediante tabela alterada
	 * Só vai modificar da linha escolhida para baixo
	 * E tudo em função dessa escolha
	 * @param tab tabela escolhida
	 */
	public void alteracoes(int tab){
		if(tab==1){
			int i = tab1Tb.getSelectedRow();
			for(int z = i; z < tab1Tb.getRowCount(); z++){
				Object valor = Float.parseFloat(tab1Tb.getValueAt(z, 0).toString()) + Float.parseFloat(tab1Tb.getValueAt(z, 1).toString()); 
				tab1Tb.setValueAt(valor, z, 2);
			}
			/**
			 * Valor da 3a coluna da tabela 1
			 * Passa a ser o valor da 1a coluna da tabela 2
			 */
			for(int z = i; z < tab2Tb.getRowCount(); z++){
				tab2Tb.setValueAt(tab1Tb.getValueAt(z, 2), z, 0);
				Object valor = Float.parseFloat(tab2Tb.getValueAt(z, 0).toString()) + 2*Float.parseFloat(tab2Tb.getValueAt(z, 1).toString()); 
				tab2Tb.setValueAt(valor, z, 2);
			}
			float res = 0;
			for(int z = 0; z < tab2Tb.getRowCount(); z++){
				res += Float.parseFloat(tab2Tb.getValueAt(z, 2).toString());
			}
			somaTf.setText(""+res);
			
		}else{
			/**
			 * Nao vai fazer nada
			 * era só para perceberes a ideia
			 */
		}
	}

	/**
	 * Somatório do total da 3a coluna da tabela 2
	 */
	private JTextField getSomaTf() {
		if (somaTf == null) {
			somaTf = new JTextField();
			somaTf.setBounds(new Rectangle(445, 263, 50, 25));
			somaTf.setEditable(false);
		}
		return somaTf;
	}
	
	public JPanel returnP(){
		return tab;
	}
}
LISTENER
package individuais;

import java.util.EventListener;

import javax.swing.event.TableModelEvent;

public interface TableModelListener extends EventListener {
	  public void tableChanged(TableModelEvent e);
	}

2 Respostas

ViniGodoy

Seu método alterações altera o setValueAt, que por sua vez altera o model. Isso dipara o listener novamente. Ao invés de fazer assim, procure entender como o model funciona, e fazer um model próprio. Isso permite que você crie colunas calculadas, sem a necessidade de listeners em todos os lugares.

Aqui existem 2 sites, com ótimo material a respeito:
http://www.informit.com/articles/article.aspx?p=332278
http://www.informit.com/articles/article.aspx?p=333472

O DefaultTableModel além de difícil de usar, torna seu código menos encapsulado e menos coeso.
Por isso essa confusão.

casconi

Obrigado!!!

Isto facilitou e bastante :smiley:

Criado 29 de dezembro de 2008
Ultima resposta 30 de dez. de 2008
Respostas 2
Participantes 2