Rekursiver TableModelListener - Bessere Lösung?

ElJarno

Bekanntes Mitglied
Hi Leute,
ich hab folgende Situtation, dass ich über einen TableModelListener den Prozentwert zu einem Betrag ausrechne und umgekehrt und diese Werte dann in das TableModel setze. Problem bei der geschichte ist, dass wenn man es nicht abfängt eine endlosschleife entsteht. Hab es bisher so gemacht dass ich die ausgerechneten Werte mit denen im Model vergleiche und erst bei unstimmigkeit die neuen in das Model eintrage. Aufgrund von rundungfehlren unfktioniert dies nicht immer. Altnetaiv würde mir noch ein statisches Flag am Anfang der Methode einfallen wie unten im Code aufgeführt oder die TM-Listener am Anfang entfernen und am Ende wieder neu draufsetzen.

Gruß Jan

Java:
	public void updateBetragProzentual(int row, Integer editedCol) {
		if (listenerFlag) {
			listenerFlag = true;
			int colBrutto = findColumn("Bruttobetrag");
			int colProz = findColumn("Gezahlt Prozentual");
			int colGez = findColumn("Gezahlter Betrag");
			Object gezValue = getValueAt(row, colGez);
			Object prozentValue = getValueAt(row, colProz);
			Object bruttoValue = getValueAt(row, colBrutto);
			if (bruttoValue != null && prozentValue != null
					&& editedCol != null && editedCol == colProz) {
				BigDecimal res = ((BigDecimal) bruttoValue)
						.multiply((BigDecimal) prozentValue);
				res = res.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
				if (gezValue == null
						|| res.compareTo((BigDecimal) gezValue) != 0)
					this.setValueAt(res, row, colGez);
			} else if (bruttoValue != null && gezValue != null
					&& editedCol != null && editedCol == colGez) {
				BigDecimal res = new BigDecimal(100)
						.multiply(((BigDecimal) gezValue));
				res = res.divide((BigDecimal) bruttoValue, 2,
						RoundingMode.HALF_UP);
				if (prozentValue == null
						|| res.compareTo((BigDecimal) prozentValue) != 0)
					this.setValueAt(res, row, colProz);
			}
			listenerFlag = false;
		}
	}
 
S

SlaterB

Gast
wenn du deine Werte eh schon rundest, kann es doch keine Abweichungen geben oder poste bitte ein Beispiel dafür,
wenn je nach Berechnungsweise mal 10.17 Euro und mal 10.18 Euro rauskommen, hast du generell ein Problem welches du klären solltest, unabhängig von den GUI-Problemen..,

mehr als dieser Vergleich oder die Flag-Lösung gibt es kaum, höchstens noch eine komplizierte Untersuchung der Aufruf-Struktur um die 'Rekursion' zu erkennen
 

Michael...

Top Contributor
Wenn ich das richtig verstanden habe, hast Du zwei Spalten, die sich gegenseitig beeinflussen.
Ich würde mir einfach merken welche Spalte zuletzt automatisch berechnet wurde, dem entsprechend auf das Event reagieren oder es ignorieren.
Java:
import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

public class TableCalcDemo extends JFrame {
	private JTable table;
	private DefaultTableModel model;
	
	private int calculatedColumn = 0;

	public TableCalcDemo() {
		model = new DefaultTableModel(new Object[][] {{100d, null, null},
				{200d, null, null}, {250d, null, null}},
				new String[] {"Betrag [€]", "Gezahlt [€]", "Gezahlt [%]" });
		table = new JTable(model) {
			public Class<?> getColumnClass(int column) {
				return Double.class;
			}
		};
		this.getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);

		model.addTableModelListener(new TableModelListener() {
			public void tableChanged(TableModelEvent evt) {
				int column = evt.getColumn();
				int row = evt.getFirstRow();
				
				System.out.println("tableChanged call by column: " + column + " | " + calculatedColumn);
				
				if (column > 0) {	
					if (model.getValueAt(row, 0)!=null && evt.getColumn()!=calculatedColumn) {
						double v1 = (Double)model.getValueAt(row, 0);
						double v2 = (Double)model.getValueAt(row, column);
						if (column==1) {
							calculatedColumn = 2;
							model.setValueAt(v2/v1*100, row, calculatedColumn);
						}
						else if (column==2) {
							calculatedColumn = 1;
							model.setValueAt(v1*(v2/100d), row, calculatedColumn);
						}
						calculatedColumn = 0;
					}
				}
				//Wenn der Bruttobetrag geändert wird ist der gezahlte Betrag ggüber dem prozentualen Betrag führend
				else { 
					if (model.getValueAt(row, 1)==null)
						return;
					double v1 = (Double)model.getValueAt(row, 0);
					double v2 = (Double)model.getValueAt(row, 1);
					calculatedColumn = 2;
					model.setValueAt(v2/v1*100, row, calculatedColumn);
					calculatedColumn = 0;
				}
			}
		});
	}

	public static void main(String[] args) {
		JFrame frame = new TableCalcDemo();
		frame.setBounds(0, 0, 500, 300);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
 

KrokoDiehl

Top Contributor
Mal anders herangegangen: Verstehe ich dein Vorhaben richtig, dass du eine Spalte (oder Zelle) in der Tabelle aktualisieren möchtest, sobald irgendwo ein anderer Wert geändert wird? Was spricht dagegen dies über die
Code:
setValueAt()
-Methode des TableModels zu machen? Damit umgehst du wahrscheinlich die potentielle Endlosschleife.
Ich meine so etwas:
Java:
class MyTableModel implements TableModel
{
    // ...

    public void setValueAt(int row, int col, Object value)
    {
        // neuen wert setzen
        meineDaten[row][col] = value;

        // ggfs Durchschnitt neu berechnen
        if ( mussDurchschnittNeuBerechnen(row, col) )
        {
            meineDaten[row][ durchschnittSpalte ] = berechneDurchschnitt(row);
            fireTableDataChanged(row, durchschnittSpalte);
        }
    }
 

ElJarno

Bekanntes Mitglied
@ SlaterB
Betrag = 7,56 davon 30 % sind gerundet 2,27. Beim nächsten führt dann 2,27 / 7,56 zu 30,03 %. Dementsprechend wird die Prozentzahl auf diesen Wert gesetzt die 2,27 bleiben aber aufrgund der Rundung stehen : 7,56*0,3003 = 2,270268.

An die anderen, danke für die Ansätze. Das überschreiben von setValueAt hört sich nicht schlecht an.

Gruß Jan
 
Ähnliche Java Themen

Ähnliche Java Themen


Oben